1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
//! Condition lists: tuples as conjunctions, plus the [`all`] and [`any`] combinators.
//!
//! A tuple of conditions *is* a condition. It renders as the parenthesized AND
//! of its elements (`(a AND b AND c)`) and has the same nullability, aggregate
//! kind and sources as a chain of [`and`](super::and) calls, so
//! `and(a, and(b, c))` can be written `(a, b, c)` anywhere a condition is
//! accepted (for example in `.r#where(...)`). Its SQL type is
//! [`Conjunction`](crate::types::Conjunction) rather than the dialect's
//! boolean. Bare tuples work up to 8 elements; use [`all`] or nested tuples
//! for longer lists.
//!
//! ```rust
//! # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
//! # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
//! # #[derive(Clone, Debug)] struct Value(String);
//! # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
//! # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
//! # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
//! # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
//! # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
//! # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
//! # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
//! # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
//! let filter = (gt(users.age, 18), is_not_null(users.email), like(users.name, "A%"));
//! assert_eq!(
//! filter.into_expr_sql().sql(),
//! r#"("users"."age" > ? AND "users"."email" IS NOT NULL AND "users"."name" LIKE ?)"#
//! );
//!
//! // OR lists use `any`.
//! let staff = any((eq(users.name, "admin"), eq(users.name, "moderator")));
//! assert_eq!(staff.sql(), r#"("users"."name" = ? OR "users"."name" = ?)"#);
//! ```
//!
//! # Optional elements
//!
//! Any element may be an [`Option`]. `None` adds nothing to the SQL, which
//! makes optional filters easy to build:
//!
//! ```rust
//! # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
//! # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
//! # #[derive(Clone, Debug)] struct Value(String);
//! # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
//! # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
//! # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
//! # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
//! # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
//! # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
//! # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
//! # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
//! let name: Option<&str> = None;
//! let filter = (gt(users.age, 18), name.map(|n| eq(users.name, n)));
//! assert_eq!(filter.into_expr_sql().sql(), r#"("users"."age" > ?)"#);
//! ```
//!
//! When *every* element is `None`, the list renders as the identity of its
//! operator: `TRUE` for a conjunction (a tuple or [`all`]) and `FALSE` for a
//! disjunction ([`any`]). An empty conjunction therefore filters nothing,
//! while an empty disjunction matches no rows instead of silently matching
//! every row.
use crateDialectTypes;
use crate;
use crateSQLParam;
use crateBooleanLike;
use ;
/// Rendered SQL for a conjunction whose elements are all absent.
const EMPTY_CONJUNCTION: &str = "TRUE";
/// Rendered SQL for a disjunction whose elements are all absent.
const EMPTY_DISJUNCTION: &str = "FALSE";
// =============================================================================
// ConditionSink
// =============================================================================
/// Collects rendered conditions while a [`ConditionList`] renders.
/// Internal to the crate.
// =============================================================================
// ConditionList
// =============================================================================
/// A tuple of conditions that [`all`] and [`any`] can combine.
///
/// Implemented for tuples of 1 to 8 elements (16 with the `col16` feature,
/// which is on by default). Each element is a boolean expression or an
/// [`Option`] of one. The list is nullable if any element is nullable, and is
/// an aggregate if any element is.
///
/// Tuples of up to 8 elements are also conditions themselves (they implement
/// [`Expr`](super::Expr)). For longer lists, use [`all`] or [`any`], or nest
/// tuples.
///
/// This trait is sealed.
// =============================================================================
// all / any
// =============================================================================
/// Logical AND of every condition in a tuple.
///
/// Renders `(a AND b AND c)`. `None` elements are skipped, and a list with no
/// present element renders as `TRUE`. The result is nullable if any element
/// is, and is an aggregate if any element is.
///
/// A bare tuple means the same thing where a condition is expected. Use `all`
/// where a tuple would be read as a list of columns instead (for example as a
/// join's `ON` condition), or for lists longer than 8.
///
/// # Examples
///
/// ```rust
/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
/// # #[derive(Clone, Debug)] struct Value(String);
/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
/// let cond = all((users.active, gt(users.age, 18)));
/// assert_eq!(cond.sql(), r#"("users"."active" AND "users"."age" > ?)"#);
///
/// let nothing = all((None::<SQLExpr<'_, Value, Int>>,));
/// assert_eq!(nothing.sql(), "TRUE");
/// ```
/// Logical OR of every condition in a tuple.
///
/// Renders `(a OR b OR c)`. `None` elements are skipped, and a list with no
/// present element renders as `FALSE`, so an empty OR matches no rows. The
/// result is nullable if any element is, and is an aggregate if any element
/// is.
///
/// # Examples
///
/// ```rust
/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
/// # #[derive(Clone, Debug)] struct Value(String);
/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
/// let cond = any((eq(users.name, "admin"), lt(users.age, 13)));
/// assert_eq!(cond.sql(), r#"("users"."name" = ? OR "users"."age" < ?)"#);
/// ```
// =============================================================================
// Tuple implementations
// =============================================================================
/// `ConditionList` for a 1-tuple: the markers are the single element's.
/// `ConditionList` for an N-tuple: delegate the marker fold to the
/// (N-1)-tuple and combine it with the last element, mirroring how
/// `RowColumnList` folds its column lists.
/// Recursive accumulator splitting the last element off the type list while
/// carrying the full type and index lists through to the impl.
/// `Expr` for a tuple of conditions: the tuple *is* the conjunction.
///
/// The tuple's `ToSQL` impl still renders a comma-separated list — that is what
/// a SELECT or GROUP BY list needs — so the conjunction is produced by the
/// expression-rendering hooks, which every condition site goes through.
/// Callback for `with_col_sizes_*!`: seals the tuple and generates its
/// `ConditionList` impl.
/// Callback for `with_col_sizes_8!`: makes a tuple usable as an expression.
with_col_sizes_8!;
// Only the first ladder rung gets an `Expr` impl. `Expr` sits at the centre of
// the trait graph — every literal, reference, `Option`, and column competes as
// a candidate — and adding tuple candidates past arity 8 makes trait selection
// blow past any usable memory budget while rustc well-formedness-checks the
// nested marker fold. Longer lists still combine through `all`/`any`, which
// need only `ConditionList`, or by nesting tuples.
with_col_sizes_8!;
// The ladder stops at 16 even when `col32` and above are enabled. The marker
// fold nests one projection per rung, and past 16 rungs rustc exhausts memory
// well-formedness-checking the impls. Column lists need the higher rungs
// because tables get wide; condition lists do not — `all`/`any` and nested
// tuples cover anything longer, and produce the same flat AND.
with_col_sizes_16!;