Skip to main content

qbrs_core/
expr.rs

1//! SQL types, columns, and the typed expression AST.
2//!
3//! `Expr<Req, S>` carries two purely phantom compile-time tags: `Req` (the
4//! flat cons-list of tables this expression touches — see `scope::Superset`)
5//! and `S` (its SQL type). The actual payload, `ExprKind`, is a plain closed
6//! enum with no generics at all, so the renderer is never re-monomorphized
7//! per query shape.
8
9use std::marker::PhantomData;
10
11use crate::scope::{Concat, Cons, MaybeNull, Nil, Table, WrapNullable};
12
13mod sql_type {
14    /// Sealed because the set really is closed: `Value` is a closed enum,
15    /// so a type this crate can't render has nothing to be — and an open
16    /// `SqlType` is what lets a schema crate pair a lying
17    /// `WrapNullable<MaybeNull>` with a column type of its own.
18    pub trait Sealed {}
19}
20
21/// A SQL scalar type. Implemented only by the closed set of leaf types
22/// declared via `sql_leaf_type!` below, plus `Nullable<T>`.
23pub trait SqlType: 'static + sql_type::Sealed {
24    type Native;
25}
26
27/// The non-generic expression payload, constructible only inside this
28/// crate: the typed `Expr<Req, S>` wrapper is the one way to build one,
29/// which is what makes its `Req`/`S` tags mean anything.
30#[derive(Debug, Clone)]
31pub(crate) enum ExprKind {
32    Column {
33        table: &'static str,
34        name: &'static str,
35    },
36    Value(Value),
37    BinOp {
38        op: BinOp,
39        lhs: Box<ExprKind>,
40        rhs: Box<ExprKind>,
41    },
42    And(Box<ExprKind>, Box<ExprKind>),
43    Or(Box<ExprKind>, Box<ExprKind>),
44    /// A condition with no operands left to check: what an empty `any_of`,
45    /// `all_of` or `is_in` means.
46    Always(bool),
47    Not(Box<ExprKind>),
48    /// `x IS NULL` / `x IS NOT NULL`. A separate node because `x = NULL` is
49    /// never true in SQL, so equality can't stand in for it.
50    IsNull {
51        expr: Box<ExprKind>,
52        negated: bool,
53    },
54    /// `x IN (a, b, ..)`. An empty list renders `FALSE`, which is what
55    /// `IN ()` means and what SQL itself won't parse.
56    InList {
57        expr: Box<ExprKind>,
58        values: Vec<ExprKind>,
59    },
60    /// `EXISTS (<subquery>)`. Held unrendered, because an `Expr` carries
61    /// no dialect: rendering it here would let a subquery written for one
62    /// dialect be filtered onto a statement of another.
63    Exists {
64        body: Box<crate::select::SelectBody>,
65        selection: Vec<crate::render::SelectItem>,
66        negated: bool,
67    },
68    /// `sql!{}`: authored text with a hole at each `?`, each hole holding an
69    /// expression the renderer recurses into — so a column in a hole is
70    /// quoted by the same code that quotes it anywhere else, and counts
71    /// toward the fragment's `Req`.
72    Template {
73        head: String,
74        rest: Vec<(ExprKind, String)>,
75    },
76    /// `CAST(expr AS type)`. The target is a kind rather than a string
77    /// because each dialect spells the type differently and the dialect
78    /// isn't known until the query renders.
79    Cast {
80        expr: Box<ExprKind>,
81        target: CastTarget,
82    },
83    /// `name(arg)`, or `name(*)` where there is no argument — the
84    /// aggregates. A real node rather than a raw fragment because an
85    /// argument is an expression the renderer has to recurse into, and
86    /// because that is what lets its column count toward the expression's
87    /// `Req`.
88    Func {
89        name: &'static str,
90        arg: Option<Box<ExprKind>>,
91    },
92    /// `func OVER (PARTITION BY .. ORDER BY ..)`. `func` is rendered
93    /// literally: it's always one of the closed set of niladic ranking
94    /// functions, so there's no sub-expression to recurse into.
95    /// `partition_by`/`order_by` *are* full `ExprKind`s, since they can
96    /// reference real columns.
97    Window {
98        func: &'static str,
99        partition_by: Vec<ExprKind>,
100        order_by: Vec<(ExprKind, SortDir)>,
101    },
102}
103
104/// Sort direction. Shared by `ORDER BY` (`select::OrderKey`) and window
105/// functions' `OVER (.. ORDER BY ..)` (`window::Window`), hence living here
106/// rather than in either module.
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108pub enum SortDir {
109    Asc,
110    Desc,
111}
112
113/// The types an aggregate is cast back into, so its result stays inside the
114/// closed set of types this crate has natives for.
115#[doc(hidden)]
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub enum CastTarget {
118    BigInt,
119    Double,
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub enum BinOp {
124    Eq,
125    Ne,
126    Lt,
127    Lte,
128    Gt,
129    Gte,
130    Like,
131}
132
133/// A closed, non-generic sum of every literal value the crate can bind as a
134/// query parameter. Deliberately not `Box<dyn ToSql>`: a plain enum keeps
135/// the renderer free of vtable dispatch and lets it stay a single
136/// non-generic function no matter how many query shapes exist.
137#[derive(Debug, Clone, PartialEq)]
138pub enum Value {
139    I32(i32),
140    I64(i64),
141    F64(f64),
142    Text(String),
143    Bool(bool),
144    Bytes(Vec<u8>),
145    /// A NULL of a specific base type, *not* a single untyped `Null`: a
146    /// Postgres bind declares a parameter type even when the value is NULL,
147    /// and a mismatched one can fail query planning. Each `NullX` variant
148    /// lets the execution layer bind `Option::<X>::None` with the right
149    /// type.
150    NullI32,
151    NullI64,
152    NullF64,
153    NullText,
154    NullBool,
155    NullBytes,
156    #[cfg(feature = "chrono")]
157    Timestamptz(chrono::DateTime<chrono::Utc>),
158    #[cfg(feature = "chrono")]
159    NullTimestamptz,
160    #[cfg(feature = "chrono")]
161    Date(chrono::NaiveDate),
162    #[cfg(feature = "chrono")]
163    NullDate,
164    #[cfg(feature = "uuid")]
165    Uuid(uuid::Uuid),
166    #[cfg(feature = "uuid")]
167    NullUuid,
168    #[cfg(feature = "decimal")]
169    Numeric(rust_decimal::Decimal),
170    #[cfg(feature = "decimal")]
171    NullNumeric,
172    /// A named placeholder in a `prepare!{}`-built query, not yet resolved
173    /// to a concrete value. It rides the existing `Vec<Value>` parameter
174    /// pipeline: rendering doesn't care what's *inside* a `Value`, only that
175    /// there's one per placeholder position. `select::Prepared` substitutes
176    /// real values before binding.
177    Placeholder(&'static str),
178}
179
180impl Value {
181    /// The SQL type this value came from, for the one error that has to name
182    /// it: a column type enabled in this crate and not in the execution
183    /// crate. Lives here because the feature-gated variants do.
184    pub fn type_name(&self) -> &'static str {
185        match self {
186            Value::I32(_) | Value::NullI32 => "Integer",
187            Value::I64(_) | Value::NullI64 => "BigInt",
188            Value::F64(_) | Value::NullF64 => "Real",
189            Value::Text(_) | Value::NullText => "Text",
190            Value::Bool(_) | Value::NullBool => "Bool",
191            Value::Bytes(_) | Value::NullBytes => "Bytes",
192            Value::Placeholder(_) => "placeholder",
193            #[cfg(feature = "chrono")]
194            Value::Timestamptz(_) | Value::NullTimestamptz => "Timestamptz",
195            #[cfg(feature = "chrono")]
196            Value::Date(_) | Value::NullDate => "Date",
197            #[cfg(feature = "uuid")]
198            Value::Uuid(_) | Value::NullUuid => "Uuid",
199            #[cfg(feature = "decimal")]
200            Value::Numeric(_) | Value::NullNumeric => "Numeric",
201        }
202    }
203}
204
205macro_rules! value_from {
206    ($ty:ty, $variant:ident) => {
207        impl From<$ty> for Value {
208            fn from(v: $ty) -> Self {
209                Value::$variant(v)
210            }
211        }
212    };
213}
214value_from!(i32, I32);
215value_from!(i64, I64);
216value_from!(f64, F64);
217value_from!(String, Text);
218value_from!(bool, Bool);
219value_from!(Vec<u8>, Bytes);
220#[cfg(feature = "chrono")]
221value_from!(chrono::DateTime<chrono::Utc>, Timestamptz);
222#[cfg(feature = "chrono")]
223value_from!(chrono::NaiveDate, Date);
224#[cfg(feature = "uuid")]
225value_from!(uuid::Uuid, Uuid);
226#[cfg(feature = "decimal")]
227value_from!(rust_decimal::Decimal, Numeric);
228
229impl From<&str> for Value {
230    fn from(v: &str) -> Self {
231        Value::Text(v.to_string())
232    }
233}
234
235/// A typed SQL expression. `Req` is the (possibly empty) flat list of
236/// tables this expression references — see the module docs and
237/// `scope::Superset` for how that's checked against a query's actual scope
238/// at the point the expression is used, not at the point it's built. This
239/// is what lets `orders::user_id.eq(users::id)` be a plain, portable value
240/// with no dependency on which query it'll eventually be used in.
241pub struct Expr<Req, S: SqlType> {
242    pub(crate) kind: ExprKind,
243    _marker: PhantomData<fn() -> (Req, S)>,
244}
245
246impl<Req, S: SqlType> Expr<Req, S> {
247    pub(crate) fn from_kind(kind: ExprKind) -> Self {
248        Expr {
249            kind,
250            _marker: PhantomData,
251        }
252    }
253}
254
255// Manual Clone: `#[derive(Clone)]` would incorrectly require `Req: Clone`
256// and `S: Clone`, even though both are purely phantom tags.
257impl<Req, S: SqlType> Clone for Expr<Req, S> {
258    fn clone(&self) -> Self {
259        Expr::from_kind(self.kind.clone())
260    }
261}
262
263/// Converts a value into a typed expression, tagging it with the set of
264/// tables it references (`Nil` for a plain literal, `Cons<T, Nil>` for a
265/// bare column, or whatever `Req` an already-built `Expr` carries).
266#[diagnostic::on_unimplemented(
267    message = "`{Self}` isn't a SQL expression",
268    label = "a column, a literal, an aggregate, or a `sql!{{}}` fragment is; a `label!` name is not",
269    note = "an `Option` isn't one either: asking about NULL is `.is_null()`, and assigning it is `null::<Text>()` — `= NULL` is never true in SQL"
270)]
271pub trait IntoExpr {
272    /// The SQL type this expression has. An associated type rather than a
273    /// parameter because every implementor has exactly one — a column its
274    /// declared type, a literal its leaf type — which is what lets a
275    /// mismatch report itself as `Comparable`/`AssignsTo` rather than as
276    /// an inference failure on a type nobody wrote.
277    type Sql: SqlType;
278    type Req;
279    fn into_expr(self) -> Expr<Self::Req, Self::Sql>;
280}
281
282impl<Req, S: SqlType> IntoExpr for Expr<Req, S> {
283    type Sql = S;
284    type Req = Req;
285    fn into_expr(self) -> Expr<Req, S> {
286        self
287    }
288}
289
290/// What an expression can be assigned *to*. The value's type is `Self` and
291/// the column's is the parameter, which is the direction assignment runs
292/// in: a `Text` value goes into a `Nullable<Text>` column and a narrower
293/// number into a wider one, never the reverse. (`Comparable` is the
294/// symmetric, nullability-blind relation, and a comparison is symmetric.)
295#[diagnostic::on_unimplemented(
296    message = "a `{Self}` expression can't be assigned to a `{Column}` column",
297    label = "the value has to fit the column: the same type, a narrower number, or a non-null value for a nullable column"
298)]
299pub trait AssignsTo<Column: SqlType>: SqlType {}
300
301impl<T: SqlType> AssignsTo<T> for T {}
302impl<T: SqlType> AssignsTo<crate::scope::Nullable<T>> for T {}
303
304mod writable {
305    /// Sealed like the other markers a derive emits: the door is
306    /// `#[doc(hidden)]`, so writing to a generated column is something a
307    /// caller can only do on purpose, never by forgetting an attribute.
308    pub trait Sealed {}
309}
310
311#[doc(hidden)]
312pub use writable::Sealed as WritableSealed;
313
314/// A column a statement may write to: `#[derive(Table)]` emits this for
315/// every column except the generated and primary-key ones, which are the
316/// same set `*Update` leaves out.
317#[diagnostic::on_unimplemented(
318    message = "`{Self}` isn't a column a statement can assign to",
319    label = "a primary-key or generated column is the database's to write, which is why `*Update` leaves it out too"
320)]
321pub trait Writable: WritableSealed {}
322
323/// A column's compile-time identity. One implementor per column in the
324/// schema, generated by `#[derive(Table)]` (and by `with!{}` for a CTE's
325/// pseudo-columns), which is what lets a column be a *key* — two columns of
326/// the same table and SQL type are still distinct types here, so a row can
327/// be indexed by column without ambiguity.
328pub trait ColumnKey: crate::row::Spelled + Copy + 'static {
329    type Table: Table;
330    type Sql: SqlType;
331}
332
333/// A column reference, identified entirely by its `ColumnKey`. Generated
334/// per-field by `#[derive(Table)]` as a `pub const NAME: Column<..>` inside
335/// each table's module (e.g. `users::id`). A plain, `Copy` value — not tied
336/// to any particular query — which is what lets it be reused across queries
337/// and passed as an ordinary function argument instead of through a
338/// scope-bound cursor closure.
339pub struct Column<C: ColumnKey>(PhantomData<C>);
340
341impl<C: ColumnKey> Column<C> {
342    pub const fn new() -> Self {
343        Column(PhantomData)
344    }
345}
346
347impl<C: ColumnKey> Default for Column<C> {
348    fn default() -> Self {
349        Self::new()
350    }
351}
352
353impl<C: ColumnKey> Clone for Column<C> {
354    fn clone(&self) -> Self {
355        *self
356    }
357}
358impl<C: ColumnKey> Copy for Column<C> {}
359
360impl<C: ColumnKey> IntoExpr for Column<C> {
361    type Sql = C::Sql;
362    type Req = Cons<C::Table, Nil>;
363    fn into_expr(self) -> Expr<Self::Req, C::Sql> {
364        Expr::from_kind(ExprKind::Column {
365            table: <C::Table as Table>::NAME,
366            name: <C as crate::row::Named>::NAME,
367        })
368    }
369}
370
371/// An expression that carries its own row key `K`: `count()` and the window
372/// functions, whose identity is the function that produced them. Selecting
373/// two of the same one into a row is what `row::Row::get` rejects, and what
374/// `LabelExt::label` exists to resolve.
375pub struct Keyed<K, Req, S: SqlType> {
376    pub(crate) kind: ExprKind,
377    _marker: PhantomData<fn() -> (K, Req, S)>,
378}
379
380impl<K, Req, S: SqlType> Keyed<K, Req, S> {
381    pub(crate) fn from_kind(kind: ExprKind) -> Self {
382        Keyed {
383            kind,
384            _marker: PhantomData,
385        }
386    }
387}
388
389impl<K, Req, S: SqlType> Clone for Keyed<K, Req, S> {
390    fn clone(&self) -> Self {
391        Keyed::from_kind(self.kind.clone())
392    }
393}
394
395impl<K, Req, S: SqlType> IntoExpr for Keyed<K, Req, S> {
396    type Sql = S;
397    type Req = Req;
398    fn into_expr(self) -> Expr<Req, S> {
399        Expr::from_kind(self.kind)
400    }
401}
402
403/// Which SQL types may be compared with each other. A nullable column and a
404/// non-nullable one hold the same values, so `users::manager_id.eq(users::id)`
405/// is an ordinary join predicate; without this relation the two would be
406/// unrelated types and every optional foreign key would be unwritable.
407///
408/// `Option` still isn't an expression, so `.eq(None)` remains unwritable:
409/// `x = NULL` is never true, and `.is_null()` is the question that was meant.
410#[diagnostic::on_unimplemented(
411    message = "`{Self}` and `{Other}` aren't comparable",
412    label = "both sides of a comparison must be the same SQL type, or two numeric ones",
413    note = "nullability doesn't matter here: a `Nullable<T>` compares with a `T`"
414)]
415pub trait Comparable<Other: SqlType>: SqlType {}
416
417impl<T: SqlType> Comparable<T> for T {}
418impl<T: SqlType> Comparable<crate::scope::Nullable<T>> for T {}
419impl<T: SqlType> Comparable<T> for crate::scope::Nullable<T> {}
420
421/// Numeric widths compare across each other, so an untyped literal doesn't
422/// have to be annotated to match the column it's tested against.
423macro_rules! comparable_across {
424    ($($a:ty => $b:ty),+ $(,)?) => {
425        $(
426            impl Comparable<$b> for $a {}
427            impl Comparable<$b> for crate::scope::Nullable<$a> {}
428            impl Comparable<crate::scope::Nullable<$b>> for $a {}
429            impl Comparable<crate::scope::Nullable<$b>> for crate::scope::Nullable<$a> {}
430        )+
431    };
432}
433comparable_across!(
434    Integer => BigInt,
435    BigInt => Integer,
436    Integer => Real,
437    Real => Integer,
438    BigInt => Real,
439    Real => BigInt,
440);
441
442macro_rules! assigns_across {
443    ($($from:ty => $to:ty),+ $(,)?) => {
444        $(
445            impl AssignsTo<$to> for $from {}
446            impl AssignsTo<crate::scope::Nullable<$to>> for $from {}
447            impl AssignsTo<crate::scope::Nullable<$to>> for crate::scope::Nullable<$from> {}
448        )+
449    };
450}
451// Widening only: an `Integer` expression fits a `BigInt` column, not the
452// other way round.
453assigns_across!(
454    Integer => BigInt,
455    Integer => Real,
456    BigInt => Real,
457);
458
459#[cfg(feature = "decimal")]
460assigns_across!(
461    Integer => Numeric,
462    BigInt => Numeric,
463    Real => Numeric,
464);
465
466// A money column is compared against a literal more than it is compared
467// against another money column, and every database this crate speaks
468// compares numeric with the integers and floats.
469#[cfg(feature = "decimal")]
470comparable_across!(
471    Numeric => Integer,
472    Integer => Numeric,
473    Numeric => BigInt,
474    BigInt => Numeric,
475    Numeric => Real,
476    Real => Numeric,
477);
478
479/// A caller-declared output-column name, generated by `label!{}`. Being a
480/// marker over `Named` is what keeps `label!{}` the only way to make one,
481/// and `Named::NAME` the only place the name is written.
482pub trait LabelKey: crate::row::Spelled + Copy + 'static {}
483
484/// An expression that has stated what it decodes to but has no name: the
485/// anonymous `Keyed`, and so selectable, labellable and usable in a slot on
486/// exactly the same terms as any other keyed expression — except that
487/// `Anon` is not `Spelled`, so it can't be looked up or matched by name.
488pub type Declared<Req, S> = Keyed<crate::row::Anon, Req, S>;
489
490impl<Req, S: SqlType> Expr<Req, S> {
491    /// States what this expression decodes to, which is what makes it
492    /// selectable: `S` was inferred from whatever built the expression, and
493    /// an inference can contradict the join the query actually has.
494    pub fn decodes_as<S2: SqlType>(self) -> Declared<Req, S2> {
495        Keyed {
496            kind: self.kind,
497            _marker: PhantomData,
498        }
499    }
500}
501
502/// A selected item filed under a `LabelKey` instead of under its own
503/// identity, and rendered with that name as its `AS`.
504pub struct Labeled<K, Inner> {
505    pub(crate) inner: Inner,
506    _key: PhantomData<fn() -> K>,
507}
508
509impl<K, Inner: Clone> Clone for Labeled<K, Inner> {
510    fn clone(&self) -> Self {
511        Labeled::new(self.inner.clone())
512    }
513}
514
515impl<K, Inner> Labeled<K, Inner> {
516    pub(crate) fn new(inner: Inner) -> Self {
517        Labeled {
518            inner,
519            _key: PhantomData,
520        }
521    }
522}
523
524/// Files a selected item under a declared name: the way to select the same
525/// expression twice, and the way out of two tables' same-named columns
526/// colliding.
527pub trait LabelExt: Sized {
528    fn label<K: LabelKey>(self, _key: K) -> Labeled<K, Self> {
529        Labeled::new(self)
530    }
531}
532impl<C: ColumnKey> LabelExt for Column<C> {}
533impl<K, Req, S: SqlType> LabelExt for Keyed<K, Req, S> {}
534// A bare `Expr` isn't selectable — it has to state its decoded type first —
535// but labelling one has to *reach* that rule to report it. Without this
536// impl, `.label(..)` on an inferred expression is a missing method and the
537// sentence about `.decodes_as::<..>()` is never printed.
538impl<Req, S: SqlType> LabelExt for Expr<Req, S> {}
539
540/// Comparison/boolean-combinator methods, blanket-implemented for anything
541/// convertible to a typed expression (columns, literals, and `Expr` itself).
542/// Kept separate from `IntoExpr` so one blanket impl can serve all three.
543// Every combinator here consumes `self`, this crate's builders being
544// by-value throughout; `is_null`/`is_in` are combinators, not predicates on
545// an existing value.
546#[allow(clippy::wrong_self_convention)]
547pub trait ExprMethods: IntoExpr + Sized {
548    fn eq<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
549    where
550        Self::Sql: Comparable<Rhs::Sql>,
551        Self::Req: Concat<Rhs::Req>,
552    {
553        bin_op(BinOp::Eq, self, rhs)
554    }
555
556    fn ne<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
557    where
558        Self::Sql: Comparable<Rhs::Sql>,
559        Self::Req: Concat<Rhs::Req>,
560    {
561        bin_op(BinOp::Ne, self, rhs)
562    }
563
564    fn lt<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
565    where
566        Self::Sql: Comparable<Rhs::Sql>,
567        Self::Req: Concat<Rhs::Req>,
568    {
569        bin_op(BinOp::Lt, self, rhs)
570    }
571
572    fn lte<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
573    where
574        Self::Sql: Comparable<Rhs::Sql>,
575        Self::Req: Concat<Rhs::Req>,
576    {
577        bin_op(BinOp::Lte, self, rhs)
578    }
579
580    fn gt<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
581    where
582        Self::Sql: Comparable<Rhs::Sql>,
583        Self::Req: Concat<Rhs::Req>,
584    {
585        bin_op(BinOp::Gt, self, rhs)
586    }
587
588    fn gte<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
589    where
590        Self::Sql: Comparable<Rhs::Sql>,
591        Self::Req: Concat<Rhs::Req>,
592    {
593        bin_op(BinOp::Gte, self, rhs)
594    }
595
596    /// `x IS NULL`. Not expressible as `.eq(..)`: comparing to NULL with `=`
597    /// yields NULL, never true, so the two are different questions.
598    fn is_null(self) -> Expr<Self::Req, Bool> {
599        Expr::from_kind(ExprKind::IsNull {
600            expr: Box::new(self.into_expr().kind),
601            negated: false,
602        })
603    }
604
605    fn is_not_null(self) -> Expr<Self::Req, Bool> {
606        Expr::from_kind(ExprKind::IsNull {
607            expr: Box::new(self.into_expr().kind),
608            negated: true,
609        })
610    }
611
612    /// `a AND b`. The boolean requirement is on the method rather than on
613    /// the receiver's type, so every spelling a condition has — a
614    /// comparison, a `sql!` fragment, a `Nullable<Bool>` column — combines
615    /// with every other, the way `.filter` accepts them all.
616    fn and<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
617    where
618        Self::Sql: BoolLike,
619        Rhs::Sql: BoolLike,
620        Self::Req: Concat<Rhs::Req>,
621    {
622        Expr::from_kind(ExprKind::And(
623            Box::new(self.into_expr().kind),
624            Box::new(rhs.into_expr().kind),
625        ))
626    }
627
628    /// `a OR b` — see `and`.
629    fn or<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
630    where
631        Self::Sql: BoolLike,
632        Rhs::Sql: BoolLike,
633        Self::Req: Concat<Rhs::Req>,
634    {
635        Expr::from_kind(ExprKind::Or(
636            Box::new(self.into_expr().kind),
637            Box::new(rhs.into_expr().kind),
638        ))
639    }
640
641    /// `x LIKE 'pattern'`. The text requirement is on the method rather
642    /// than on a trait of its own, so a non-text operand reports `TextLike`
643    /// instead of a missing method.
644    fn like<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
645    where
646        Self::Sql: TextLike,
647        Rhs::Sql: TextLike,
648        Self::Req: Concat<Rhs::Req>,
649    {
650        bin_op(BinOp::Like, self, rhs)
651    }
652
653    /// `x IN (a, b, ..)` over a runtime-length list of literals, each bound
654    /// as its own parameter. An empty list renders `FALSE`.
655    ///
656    /// **Known limitation**: the list holds values, not expressions — a
657    /// column reference on the right needs the table it belongs to folded
658    /// into `Req`, which is the same design `sql!{}` covers today.
659    fn is_in<I>(self, values: I) -> Expr<Self::Req, Bool>
660    where
661        I: IntoIterator,
662        I::Item: IntoExpr<Req = Nil>,
663        Self::Sql: Comparable<<I::Item as IntoExpr>::Sql>,
664    {
665        let values: Vec<ExprKind> = values.into_iter().map(|v| v.into_expr().kind).collect();
666        // `IN ()` is not SQL, and matching nothing is what it would mean.
667        if values.is_empty() {
668            return Expr::from_kind(ExprKind::Always(false));
669        }
670        Expr::from_kind(ExprKind::InList {
671            expr: Box::new(self.into_expr().kind),
672            values,
673        })
674    }
675}
676
677/// True when any of the conditions is. Takes a runtime-length collection,
678/// the way `is_in` takes a runtime-length list of values, so the `OR` a
679/// search box needs doesn't have to be folded by hand — folding one by one
680/// grows `Req` and stops type-checking after the first pair. An empty
681/// collection matches nothing, which is what `is_in([])` says too.
682pub fn any_of<Req, C: IntoExpr<Req = Req>>(conds: impl IntoIterator<Item = C>) -> Expr<Req, Bool>
683where
684    C::Sql: BoolLike,
685{
686    combine(conds, false)
687}
688
689/// True when all of them are. An empty collection matches everything, which
690/// is what a `WHERE` with no conditions does.
691pub fn all_of<Req, C: IntoExpr<Req = Req>>(conds: impl IntoIterator<Item = C>) -> Expr<Req, Bool>
692where
693    C::Sql: BoolLike,
694{
695    combine(conds, true)
696}
697
698fn combine<Req, C: IntoExpr<Req = Req>>(
699    conds: impl IntoIterator<Item = C>,
700    all: bool,
701) -> Expr<Req, Bool>
702where
703    C::Sql: BoolLike,
704{
705    Expr::from_kind(fold_conditions(
706        conds.into_iter().map(|c| c.into_expr().kind),
707        all,
708    ))
709}
710
711/// AND- or OR-folds conditions, answering `TRUE`/`FALSE` for an empty
712/// collection — "all of nothing" matches everything, "any of nothing"
713/// matches nothing. Shared with `select::Predicate`, which folds the same
714/// way once the scope requirement is discharged.
715pub(crate) fn fold_conditions(kinds: impl IntoIterator<Item = ExprKind>, all: bool) -> ExprKind {
716    let mut folded: Option<ExprKind> = None;
717    for kind in kinds {
718        folded = Some(match folded {
719            None => kind,
720            Some(acc) if all => ExprKind::And(Box::new(acc), Box::new(kind)),
721            Some(acc) => ExprKind::Or(Box::new(acc), Box::new(kind)),
722        });
723    }
724    folded.unwrap_or(ExprKind::Always(all))
725}
726
727impl<T: IntoExpr> ExprMethods for T {}
728
729fn bin_op<Lhs, Rhs>(
730    op: BinOp,
731    lhs: Lhs,
732    rhs: Rhs,
733) -> Expr<<Lhs::Req as Concat<Rhs::Req>>::Output, Bool>
734where
735    Lhs: IntoExpr,
736    Rhs: IntoExpr,
737    Lhs::Req: Concat<Rhs::Req>,
738{
739    Expr::from_kind(ExprKind::BinOp {
740        op,
741        lhs: Box::new(lhs.into_expr().kind),
742        rhs: Box::new(rhs.into_expr().kind),
743    })
744}
745
746/// What `LIKE` accepts: a text expression, nullable or not. Its own marker
747/// rather than `Comparable<Text>` so the failure says what the operator
748/// needs instead of talking about comparison.
749#[diagnostic::on_unimplemented(
750    message = "`LIKE` needs a text expression, and `{Self}` isn't one",
751    label = "only `Text` and `Nullable<Text>` columns and expressions accept `.like(..)`"
752)]
753pub trait TextLike: SqlType {}
754
755impl TextLike for Text {}
756impl TextLike for crate::scope::Nullable<Text> {}
757
758/// What a `WHERE`/`HAVING`/`ON` clause accepts. `Nullable<Bool>` belongs
759/// here because SQL takes it: a NULL condition selects no row, which is
760/// the same answer `IS NOT TRUE` would give.
761#[diagnostic::on_unimplemented(
762    message = "a condition has to be a boolean expression, and `{Self}` isn't one",
763    label = "expected `Bool` or `Nullable<Bool>`"
764)]
765pub trait BoolLike: SqlType {}
766
767impl BoolLike for Bool {}
768impl BoolLike for crate::scope::Nullable<Bool> {}
769
770/// `!condition`, not `condition.not()`: the standard `Not` trait reads more
771/// naturally at call sites than a same-named inherent method. Implemented
772/// for all three spellings `.filter` takes, each keeping its own type —
773/// `NOT` of a `Nullable<Bool>` is still nullable, and a `sql!` fragment
774/// stays the same fragment.
775impl<Req, S: BoolLike> std::ops::Not for Expr<Req, S> {
776    type Output = Expr<Req, S>;
777    fn not(self) -> Self::Output {
778        Expr::from_kind(ExprKind::Not(Box::new(self.kind)))
779    }
780}
781
782impl<K, Req, S: BoolLike> std::ops::Not for Keyed<K, Req, S> {
783    type Output = Keyed<K, Req, S>;
784    fn not(self) -> Self::Output {
785        Keyed::from_kind(ExprKind::Not(Box::new(self.kind)))
786    }
787}
788
789impl<C: ColumnKey> std::ops::Not for Column<C>
790where
791    C::Sql: BoolLike,
792{
793    type Output = Expr<Cons<C::Table, Nil>, C::Sql>;
794    fn not(self) -> Self::Output {
795        Expr::from_kind(ExprKind::Not(Box::new(self.into_expr().kind)))
796    }
797}
798
799/// A base SQL type's typed NULL — see `Value::NullI32` etc. for why this
800/// can't just be a single untyped `Value::Null`.
801pub trait NullValue: SqlType {
802    const NULL_VALUE: Value;
803}
804
805/// A typed SQL `NULL`, for the one position an `Option` can't say it:
806/// `SET column = NULL` assigns, and an assignment has no `Option` to be
807/// `None`. `null::<Text>()` is `Nullable<Text>`, so only a nullable column
808/// accepts it.
809pub fn null<S: NullValue>() -> Expr<Nil, crate::scope::Nullable<S>> {
810    Expr::from_kind(ExprKind::Value(S::NULL_VALUE))
811}
812
813/// Declares a leaf (base) SQL type: the marker struct, its `SqlType` impl,
814/// its `WrapNullable<MaybeNull>` impl, and `IntoExpr` from its native Rust
815/// type. One concrete, non-generic impl per type — a blanket
816/// `impl<T: SqlType> WrapNullable<MaybeNull> for T` would conflict with
817/// `Nullable<T>`'s own impl (see `scope::WrapNullable`).
818mod raw_arg {
819    /// Sealed for the reason `select::ColumnList` is: `Req` is a free
820    /// parameter, and a slot's value can be delegated to a real column — so
821    /// a hand-written impl could claim `Nil` while naming a table, which is
822    /// exactly the scope check a `sql!` slot exists to keep.
823    pub trait Sealed {}
824    impl<T: super::IntoExpr> Sealed for T {}
825}
826
827macro_rules! sql_leaf_type {
828    ($name:ident, $native:ty, $null_variant:ident) => {
829        pub struct $name;
830
831        impl sql_type::Sealed for $name {}
832
833        impl SqlType for $name {
834            type Native = $native;
835        }
836
837        impl crate::scope::wrap::Sealed<MaybeNull> for $name {}
838
839        impl crate::scope::WrapNullable<MaybeNull> for $name {
840            type Output = crate::scope::Nullable<$name>;
841        }
842
843        impl IntoExpr for $native {
844            type Sql = $name;
845            type Req = Nil;
846            fn into_expr(self) -> Expr<Nil, $name> {
847                Expr::from_kind(ExprKind::Value(Value::from(self)))
848            }
849        }
850
851        impl crate::select::SingleColumn for $native {}
852        impl crate::select::SingleColumn for ::std::option::Option<$native> {}
853
854        impl NullValue for $name {
855            const NULL_VALUE: Value = Value::$null_variant;
856        }
857
858        impl crate::insert::IntoColumnValue<$native> for $native {
859            fn into_column_value(self) -> $native {
860                self
861            }
862        }
863
864        impl crate::insert::IntoColumnValue<::std::option::Option<$native>> for $native {
865            fn into_column_value(self) -> ::std::option::Option<$native> {
866                ::std::option::Option::Some(self)
867            }
868        }
869
870        impl crate::insert::IntoColumnValue<::std::option::Option<$native>>
871            for ::std::option::Option<$native>
872        {
873            fn into_column_value(self) -> ::std::option::Option<$native> {
874                self
875            }
876        }
877
878        impl crate::insert::IntoColumnValue<crate::insert::Defaultable<$native>> for $native {
879            fn into_column_value(self) -> crate::insert::Defaultable<$native> {
880                crate::insert::Defaultable::Value(self)
881            }
882        }
883
884        impl crate::insert::IntoColumnValue<crate::insert::Defaultable<$native>>
885            for ::std::option::Option<$native>
886        {
887            fn into_column_value(self) -> crate::insert::Defaultable<$native> {
888                match self {
889                    ::std::option::Option::Some(v) => crate::insert::Defaultable::Value(v),
890                    ::std::option::Option::None => crate::insert::Defaultable::Default,
891                }
892            }
893        }
894
895        impl
896            crate::insert::IntoColumnValue<
897                crate::insert::Defaultable<::std::option::Option<$native>>,
898            > for $native
899        {
900            fn into_column_value(
901                self,
902            ) -> crate::insert::Defaultable<::std::option::Option<$native>> {
903                crate::insert::Defaultable::Value(::std::option::Option::Some(self))
904            }
905        }
906
907        impl
908            crate::insert::IntoColumnValue<
909                crate::insert::Defaultable<::std::option::Option<$native>>,
910            > for ::std::option::Option<$native>
911        {
912            fn into_column_value(
913                self,
914            ) -> crate::insert::Defaultable<::std::option::Option<$native>> {
915                match self {
916                    ::std::option::Option::Some(v) => {
917                        crate::insert::Defaultable::Value(::std::option::Option::Some(v))
918                    }
919                    ::std::option::Option::None => crate::insert::Defaultable::Default,
920                }
921            }
922        }
923
924        impl raw_arg::Sealed for ::std::option::Option<$native> {}
925
926        impl RawArg for ::std::option::Option<$native> {
927            type Req = Nil;
928            fn into_raw_arg(self) -> RawSlot {
929                RawSlot(ExprKind::Value(Value::from(self)))
930            }
931        }
932
933        impl crate::row::SameShape<$native> for $native {}
934        impl crate::row::SameShape<::std::option::Option<$native>>
935            for ::std::option::Option<$native>
936        {
937        }
938
939        // A nullable `prepare!{}` parameter binds through here, which is what
940        // the typed `NullX` variants exist for.
941        impl From<::std::option::Option<$native>> for Value {
942            fn from(v: ::std::option::Option<$native>) -> Self {
943                match v {
944                    ::std::option::Option::Some(x) => Value::from(x),
945                    ::std::option::Option::None => Value::$null_variant,
946                }
947            }
948        }
949    };
950}
951
952sql_leaf_type!(Integer, i32, NullI32);
953sql_leaf_type!(BigInt, i64, NullI64);
954sql_leaf_type!(Real, f64, NullF64);
955sql_leaf_type!(Text, String, NullText);
956sql_leaf_type!(Bool, bool, NullBool);
957sql_leaf_type!(Bytes, Vec<u8>, NullBytes);
958
959// Types a database has and Rust doesn't: each decodes to the crate its
960// feature names, so a schema that has no `timestamptz` column pays for none
961// of it.
962#[cfg(feature = "chrono")]
963sql_leaf_type!(Timestamptz, chrono::DateTime<chrono::Utc>, NullTimestamptz);
964#[cfg(feature = "chrono")]
965sql_leaf_type!(Date, chrono::NaiveDate, NullDate);
966#[cfg(feature = "uuid")]
967sql_leaf_type!(Uuid, uuid::Uuid, NullUuid);
968#[cfg(feature = "decimal")]
969sql_leaf_type!(Numeric, rust_decimal::Decimal, NullNumeric);
970
971// Ergonomic extra: allow `&str` literals directly, without forcing
972// `.to_string()` at every call site.
973impl IntoExpr for &String {
974    type Sql = Text;
975    type Req = Nil;
976    fn into_expr(self) -> Expr<Nil, Text> {
977        Expr::from_kind(ExprKind::Value(Value::Text(self.clone())))
978    }
979}
980
981impl IntoExpr for &str {
982    type Sql = Text;
983    type Req = Nil;
984    fn into_expr(self) -> Expr<Nil, Text> {
985        Expr::from_kind(ExprKind::Value(Value::Text(self.to_string())))
986    }
987}
988
989/// Text's borrowed forms, at every slot a `String` column has. The leaf
990/// macro can't generate these: only `Text` has a borrowed spelling.
991macro_rules! text_column_value {
992    ($borrowed:ty) => {
993        impl crate::insert::IntoColumnValue<String> for $borrowed {
994            fn into_column_value(self) -> String {
995                self.to_string()
996            }
997        }
998
999        impl crate::insert::IntoColumnValue<Option<String>> for $borrowed {
1000            fn into_column_value(self) -> Option<String> {
1001                Some(self.to_string())
1002            }
1003        }
1004
1005        impl crate::insert::IntoColumnValue<crate::insert::Defaultable<String>> for $borrowed {
1006            fn into_column_value(self) -> crate::insert::Defaultable<String> {
1007                crate::insert::Defaultable::Value(self.to_string())
1008            }
1009        }
1010
1011        impl crate::insert::IntoColumnValue<crate::insert::Defaultable<Option<String>>>
1012            for $borrowed
1013        {
1014            fn into_column_value(self) -> crate::insert::Defaultable<Option<String>> {
1015                crate::insert::Defaultable::Value(Some(self.to_string()))
1016            }
1017        }
1018    };
1019}
1020
1021text_column_value!(&str);
1022text_column_value!(&String);
1023
1024impl<S: SqlType> sql_type::Sealed for crate::scope::Nullable<S> {}
1025
1026impl<S: SqlType> SqlType for crate::scope::Nullable<S> {
1027    type Native = Option<S::Native>;
1028}
1029
1030crate::row::expr_key!(
1031    Count,
1032    HasCount,
1033    count,
1034    "The identity a selected `count(*)` is filed under in a row.",
1035    'c',
1036    'o',
1037    'u',
1038    'n',
1039    't'
1040);
1041
1042/// `count(*)` as a rendered selection item, for `Select::count_sql`.
1043pub(crate) fn count_item() -> crate::render::SelectItem {
1044    crate::render::SelectItem::bare(count_star())
1045}
1046
1047fn count_star() -> ExprKind {
1048    ExprKind::Func {
1049        name: "count",
1050        arg: None,
1051    }
1052}
1053
1054/// Counts rows. `count_of(column)` counts that column's non-NULL values,
1055/// which is the different question a `LEFT JOIN` makes visible.
1056pub fn count() -> Keyed<Count, Nil, BigInt> {
1057    Keyed::from_kind(count_star())
1058}
1059
1060/// What `min`/`max` accept: a type the databases order. Its own marker for
1061/// the reason `Summable` is one — `WrapNullable<MaybeNull>`, which stood
1062/// here before, is implemented for every leaf type, so it gated nothing and
1063/// `max(bool_column)` rendered SQL Postgres has no aggregate for.
1064///
1065/// The set is Postgres's, the narrowest of the three: no `boolean`, no
1066/// `bytea`, and no `uuid` before PG 18.
1067#[diagnostic::on_unimplemented(
1068    message = "`min`/`max` need an ordered expression, and `{Self}` isn't one",
1069    label = "numbers, text, and dates/timestamps are ordered; booleans, bytes and UUIDs are not — `bool_or`/`bool_and` are the aggregate a flag wants, and aren't built yet"
1070)]
1071pub trait Ordered: SqlType + WrapNullable<MaybeNull> {}
1072
1073impl Ordered for Integer {}
1074impl Ordered for BigInt {}
1075impl Ordered for Real {}
1076impl Ordered for Text {}
1077#[cfg(feature = "decimal")]
1078impl Ordered for Numeric {}
1079#[cfg(feature = "chrono")]
1080impl Ordered for Timestamptz {}
1081#[cfg(feature = "chrono")]
1082impl Ordered for Date {}
1083
1084/// A nullable column orders like its base type — the NULLs sort, they don't
1085/// stop the aggregate from existing.
1086impl<S: Ordered> Ordered for crate::scope::Nullable<S> {}
1087
1088/// What `sum(..)` of a column decodes to. `sum` is NULL over zero rows, so
1089/// every result is nullable however the column was declared.
1090/// `CAST` keeps the widened type a database picks for a sum inside the
1091/// closed set of types this crate has: Postgres returns `numeric` for
1092/// `sum(bigint)` and `avg(int)`, neither of which has a native here.
1093#[diagnostic::on_unimplemented(
1094    message = "`sum`/`avg` need a numeric expression, and `{Self}` isn't one",
1095    label = "only `Integer`, `BigInt` and `Real` columns and expressions (and `Numeric`, with the `decimal` feature) can be summed or averaged"
1096)]
1097pub trait Summable: SqlType {
1098    type Sum: SqlType;
1099    const SUM_CAST: Option<CastTarget>;
1100    const AVG_CAST: Option<CastTarget> = Some(CastTarget::Double);
1101}
1102impl Summable for Integer {
1103    type Sum = crate::scope::Nullable<BigInt>;
1104    const SUM_CAST: Option<CastTarget> = None;
1105}
1106impl Summable for BigInt {
1107    type Sum = crate::scope::Nullable<BigInt>;
1108    const SUM_CAST: Option<CastTarget> = Some(CastTarget::BigInt);
1109}
1110impl Summable for Real {
1111    type Sum = crate::scope::Nullable<Real>;
1112    const SUM_CAST: Option<CastTarget> = None;
1113    const AVG_CAST: Option<CastTarget> = None;
1114}
1115// `sum(numeric)` stays numeric, so it needs no cast; `avg` decodes as `f64`
1116// for every column type, so a numeric one is cast like the rest.
1117#[cfg(feature = "decimal")]
1118impl Summable for Numeric {
1119    type Sum = crate::scope::Nullable<Numeric>;
1120    const SUM_CAST: Option<CastTarget> = None;
1121    const AVG_CAST: Option<CastTarget> = Some(CastTarget::Double);
1122}
1123impl<T: Summable> Summable for crate::scope::Nullable<T> {
1124    type Sum = T::Sum;
1125    const SUM_CAST: Option<CastTarget> = T::SUM_CAST;
1126    const AVG_CAST: Option<CastTarget> = T::AVG_CAST;
1127}
1128
1129/// The row key an aggregate over `C` is filed under: distinct per function
1130/// *and* per column, so `sum(a)` and `sum(b)` don't collide, and named after
1131/// the column so a DTO field or a CTE column can match it.
1132pub struct Agg<Op, C>(PhantomData<fn() -> (Op, C)>);
1133
1134// An aggregate is filed under the column it aggregates: `sum(orders::total)`
1135// reads back as `total`, and matches a CTE or DTO field of that name.
1136//
1137// **Known limitation**: by *name*, not by key — `Agg<Sum, total>` is its own
1138// key type, so `row.get(sum(orders::total))` and `#[derive(FromRow)]` find
1139// it and the generated `row.total()` accessor does not.
1140#[doc(hidden)]
1141impl<Op, C: crate::row::Named> crate::row::NamedSealed for Agg<Op, C> {}
1142
1143#[doc(hidden)]
1144impl<Op: 'static, C: crate::row::Named + 'static> crate::row::Named for Agg<Op, C> {
1145    type Name = <C as crate::row::Named>::Name;
1146    const NAME: &'static str = <C as crate::row::Named>::NAME;
1147}
1148
1149#[doc(hidden)]
1150impl<Op: 'static, C: crate::row::Spelled + 'static> crate::row::Spelled for Agg<Op, C> {}
1151
1152fn aggregate_kind<C: ColumnKey>(name: &'static str, cast: Option<CastTarget>) -> ExprKind {
1153    let call = ExprKind::Func {
1154        name,
1155        arg: Some(Box::new(ExprKind::Column {
1156            table: <C::Table as Table>::NAME,
1157            name: <C as crate::row::Named>::NAME,
1158        })),
1159    };
1160    match cast {
1161        Some(target) => ExprKind::Cast {
1162            expr: Box::new(call),
1163            target,
1164        },
1165        None => call,
1166    }
1167}
1168
1169macro_rules! aggregate {
1170    ($op:ident, $func:ident, $sql:literal, $out:ty, $bound:path, $cast:expr, $doc:literal) => {
1171        #[doc = $doc]
1172        pub struct $op;
1173
1174        #[doc = $doc]
1175        pub fn $func<C: ColumnKey>(
1176            _column: Column<C>,
1177        ) -> Keyed<Agg<$op, C>, Cons<C::Table, Nil>, $out>
1178        where
1179            C::Sql: $bound,
1180            $out: SqlType,
1181        {
1182            Keyed::from_kind(aggregate_kind::<C>($sql, $cast))
1183        }
1184    };
1185}
1186
1187aggregate!(
1188    Sum,
1189    sum,
1190    "sum",
1191    <C::Sql as Summable>::Sum,
1192    Summable,
1193    <C::Sql as Summable>::SUM_CAST,
1194    "`sum(column)`. NULL over zero rows, so the result is always nullable."
1195);
1196aggregate!(
1197    Min,
1198    min,
1199    "min",
1200    <C::Sql as WrapNullable<MaybeNull>>::Output,
1201    Ordered,
1202    None,
1203    "`min(column)`. NULL over zero rows."
1204);
1205aggregate!(
1206    Max,
1207    max,
1208    "max",
1209    <C::Sql as WrapNullable<MaybeNull>>::Output,
1210    Ordered,
1211    None,
1212    "`max(column)`. NULL over zero rows."
1213);
1214aggregate!(
1215    Avg,
1216    avg,
1217    "avg",
1218    crate::scope::Nullable<Real>,
1219    Summable,
1220    <C::Sql as Summable>::AVG_CAST,
1221    "`avg(column)`. NULL over zero rows."
1222);
1223aggregate!(
1224    CountOf,
1225    count_of,
1226    "count",
1227    BigInt,
1228    SqlType,
1229    None,
1230    "`count(column)` — non-NULL values, unlike `count()`'s `count(*)` rows."
1231);
1232
1233/// One `?` slot of a `sql!{}` fragment: every expression, plus the `Option`
1234/// a request field already holds — a slot is the one place a NULL arrives
1235/// as data rather than as a written `null::<..>()`. A slot that isn't one
1236/// reports `IntoExpr`, since that is the bound this one is built on.
1237pub trait RawArg: raw_arg::Sealed {
1238    type Req;
1239    #[doc(hidden)]
1240    fn into_raw_arg(self) -> RawSlot;
1241}
1242
1243impl<T: IntoExpr> RawArg for T {
1244    type Req = T::Req;
1245    fn into_raw_arg(self) -> RawSlot {
1246        RawSlot(self.into_expr().kind)
1247    }
1248}
1249
1250/// What a slot holds, opaque outside this crate: the `RawArg` impls are the
1251/// only way to make one, so a slot always holds something the renderer can
1252/// write.
1253pub struct RawSlot(ExprKind);
1254
1255impl RawSlot {
1256    fn into_kind(self) -> ExprKind {
1257        self.0
1258    }
1259}
1260
1261/// The whole slot list of one `sql!{}`, whose `Req` is every table its
1262/// slots name.
1263#[diagnostic::on_unimplemented(
1264    message = "a `sql!` fragment takes at most 8 `?` slots",
1265    label = "split the fragment, or fold part of it into the builder"
1266)]
1267pub trait RawArgs {
1268    type Req;
1269    #[doc(hidden)]
1270    fn into_raw_args(self) -> Vec<RawSlot>;
1271}
1272
1273impl RawArgs for () {
1274    type Req = Nil;
1275    fn into_raw_args(self) -> Vec<RawSlot> {
1276        Vec::new()
1277    }
1278}
1279
1280macro_rules! raw_args_tuple {
1281    ($head:ident $(, $rest:ident)*) => {
1282        #[allow(non_snake_case)]
1283        impl<$head: RawArg $(, $rest: RawArg)*> RawArgs for ($head, $($rest,)*)
1284        where
1285            ($($rest,)*): RawArgs,
1286            $head::Req: Concat<<($($rest,)*) as RawArgs>::Req>,
1287        {
1288            type Req = <$head::Req as Concat<<($($rest,)*) as RawArgs>::Req>>::Output;
1289            fn into_raw_args(self) -> Vec<RawSlot> {
1290                let ($head, $($rest,)*) = self;
1291                let mut kinds = ::std::vec![RawArg::into_raw_arg($head)];
1292                kinds.extend(RawArgs::into_raw_args(($($rest,)*)));
1293                kinds
1294            }
1295        }
1296    };
1297}
1298raw_args_tuple!(A);
1299raw_args_tuple!(A, B);
1300raw_args_tuple!(A, B, C);
1301raw_args_tuple!(A, B, C, D);
1302raw_args_tuple!(A, B, C, D, E);
1303raw_args_tuple!(A, B, C, D, E, F);
1304raw_args_tuple!(A, B, C, D, E, F, G);
1305raw_args_tuple!(A, B, C, D, E, F, G, H);
1306
1307/// Counts the `?` slots in a `sql!` text, so the macro can compare that
1308/// count with the number of arguments it was handed while both are still
1309/// constants.
1310#[doc(hidden)]
1311pub const fn placeholder_count(sql: &str) -> usize {
1312    let bytes = sql.as_bytes();
1313    let mut i = 0;
1314    let mut count = 0;
1315    while i < bytes.len() {
1316        if bytes[i] == b'?' {
1317            count += 1;
1318        }
1319        i += 1;
1320    }
1321    count
1322}
1323
1324/// The one door into `ExprKind` from outside the crate, and the only shape
1325/// that needs one: `sql!{}` expands in the caller's. `Req` is the union of
1326/// the slots' own, so a fragment carries exactly the tables its `?`s name.
1327/// Reached through `sql!`, which is what checks that every `?` has a value.
1328#[doc(hidden)]
1329pub fn raw_expr<S: SqlType, Args: RawArgs>(
1330    sql: &'static str,
1331    args: Args,
1332) -> Declared<Args::Req, S> {
1333    Keyed::from_kind(template(sql, args.into_raw_args()))
1334}
1335
1336/// Splits authored text on its `?` slots and pairs each with its argument.
1337/// `sql!` checks the two counts against each other while both are still
1338/// constants, which is why leftovers here can't happen through it.
1339fn template(sql: &'static str, args: Vec<RawSlot>) -> ExprKind {
1340    let mut pieces: Vec<String> = vec![String::new()];
1341    for c in sql.chars() {
1342        match c {
1343            '?' => pieces.push(String::new()),
1344            c => pieces.last_mut().expect("one piece to start").push(c),
1345        }
1346    }
1347
1348    let mut pieces = pieces.into_iter();
1349    let head = pieces.next().unwrap_or_default();
1350    let rest = args
1351        .into_iter()
1352        .map(RawSlot::into_kind)
1353        .zip(pieces)
1354        .collect();
1355    ExprKind::Template { head, rest }
1356}
1357
1358/// A named, typed placeholder: usable anywhere a value of type `S` is
1359/// expected (`.eq(placeholder::<Integer>("id"))`), rendered as a normal
1360/// bound parameter but resolved to a concrete value at
1361/// `Prepared::load()` time. `prepare!{}` is the intended entry point
1362/// rather than this function, since it also generates the typed `Params`
1363/// struct that makes a missing or misspelled placeholder a compile error.
1364#[doc(hidden)]
1365pub fn placeholder<S: SqlType>(name: &'static str) -> Expr<Nil, S> {
1366    Expr::from_kind(ExprKind::Value(Value::Placeholder(name)))
1367}