Skip to main content

qbrs_core/select/
mod.rs

1//! The `SELECT` builder: `select(..).from(..).join(..).filter(..)
2//! .order_by(..).limit(..)`, in SQL keyword order, with tables passed as
3//! arguments rather than by turbofish.
4
5use std::marker::PhantomData;
6
7use crate::cte::Cte;
8use crate::dialect::{Dialect, SupportsFullOuterJoin, SupportsRightJoin};
9use crate::expr::{BoolLike, Comparable, Expr, ExprKind, IntoExpr, Value};
10use crate::render::{
11    Fragment, FragmentSink, QuerySink, SelectItem, Sink, render_and_list, render_expr,
12    render_expr_list, render_order_by, render_select_list,
13};
14use crate::row::{Field as RowFieldLookup, LookupKey, Row};
15use crate::scope::{
16    BaseTable, Concat, Cons, MapNullable, MaybeNull, Nil, NotNull, Position, ScopeTables, Superset,
17    Table, TableSlot,
18};
19
20mod dyn_select;
21mod prepared;
22mod selection;
23mod set_op;
24
25pub use crate::expr::SortDir;
26pub use dyn_select::{CannotFilterAfterErase, DynSelect};
27pub use prepared::{Prepared, PreparedParams, Total, UnresolvedPlaceholder};
28pub use selection::{
29    All, AllColumns, ColumnList, RowField, SelectableSealed, Selection, SelectionPart, SingleColumn,
30};
31pub use set_op::SetOp;
32
33/// One `name AS (body)` binding, carried in by the `Cte` a query was
34/// entered through. Opaque outside this crate: `JoinSource::binding` is the
35/// only way to make one, and it takes the name and columns from the
36/// marker's `CteShape` rather than from anything a caller can vary.
37#[doc(hidden)]
38#[derive(Debug, Clone)]
39pub struct CteDef {
40    name: &'static str,
41    column_names: Vec<&'static str>,
42    body: Fragment,
43}
44
45impl CteDef {
46    pub(crate) fn new(name: &'static str, column_names: Vec<&'static str>, body: Fragment) -> Self {
47        CteDef {
48            name,
49            column_names,
50            body,
51        }
52    }
53}
54
55#[derive(Debug, Clone)]
56enum JoinKind {
57    Inner,
58    Left,
59    Right,
60    Full,
61}
62
63#[derive(Debug, Clone)]
64struct JoinClause {
65    kind: JoinKind,
66    table: &'static str,
67    on: ExprKind,
68}
69
70/// An order-by key: a column/expression tagged with a direction. Built via
71/// `.asc()`/`.desc()` on any column or expression (see `OrderExt` below),
72/// so `.order_by(users::created_at.desc())` reads as one argument, not two.
73pub struct OrderKey<Req> {
74    kind: ExprKind,
75    dir: SortDir,
76    _marker: PhantomData<fn() -> Req>,
77}
78
79// Hand-written for the reason `Expr`'s is: `#[derive(Clone)]` would ask the
80// phantom `Req` to be `Clone`, which no scope list is.
81impl<Req> Clone for OrderKey<Req> {
82    fn clone(&self) -> Self {
83        OrderKey {
84            kind: self.kind.clone(),
85            dir: self.dir,
86            _marker: PhantomData,
87        }
88    }
89}
90
91impl<Req> OrderKey<Req> {
92    pub(crate) fn into_parts(self) -> (ExprKind, SortDir) {
93        (self.kind, self.dir)
94    }
95}
96
97pub trait OrderExt: IntoExpr + Sized {
98    fn asc(self) -> OrderKey<Self::Req> {
99        OrderKey {
100            kind: self.into_expr().kind,
101            dir: SortDir::Asc,
102            _marker: PhantomData,
103        }
104    }
105    /// The direction as a value, for a sort order that arrives at runtime —
106    /// `?dir=desc` — instead of an N-way match over `.asc()`/`.desc()`.
107    fn sort(self, dir: SortDir) -> OrderKey<Self::Req> {
108        OrderKey {
109            kind: self.into_expr().kind,
110            dir,
111            _marker: PhantomData,
112        }
113    }
114    fn desc(self) -> OrderKey<Self::Req> {
115        OrderKey {
116            kind: self.into_expr().kind,
117            dir: SortDir::Desc,
118            _marker: PhantomData,
119        }
120    }
121}
122impl<T: IntoExpr> OrderExt for T {}
123
124/// Something a query can select from or join to. A schema table brings
125/// nothing with it; a `Cte` brings its `WITH` binding, so attaching that
126/// binding and putting the pseudo-table in scope stay one act — while every
127/// join kind, and `correlated`, work on both without being written twice.
128pub trait JoinSource<D>: join_source::Sealed {
129    /// The table this source contributes to the scope.
130    type Table: Table;
131    /// The `WITH` binding this source carries into the statement — `None`
132    /// for a schema table, which is already there.
133    #[doc(hidden)]
134    fn binding(self) -> Option<CteDef>;
135}
136
137mod join_source {
138    /// Sealed the way `dialect::Dialect` is: what a query can read from is
139    /// a closed set of two, a schema table and a bound CTE.
140    pub trait Sealed {}
141    impl<T: super::BaseTable> Sealed for T {}
142    impl<D, Marker> Sealed for crate::cte::Cte<D, Marker> {}
143}
144
145impl<D, T: BaseTable> JoinSource<D> for T {
146    type Table = T;
147    fn binding(self) -> Option<CteDef> {
148        None
149    }
150}
151
152impl<D, Marker: crate::cte::CteShape> JoinSource<D> for Cte<D, Marker> {
153    type Table = Marker;
154    fn binding(self) -> Option<CteDef> {
155        Some(CteDef::new(
156            <Marker as Table>::NAME,
157            <Marker::Row as crate::row::ColumnNames>::names(),
158            self.into_body(),
159        ))
160    }
161}
162
163/// Something a query can be ordered by: an `OrderKey` whose tables this
164/// scope contains, or a `SortKey` already discharged against it — the same
165/// pair `Condition` makes for `.filter`.
166#[diagnostic::on_unimplemented(
167    message = "`{Self}` isn't a sort key",
168    label = "a column or expression with `.asc()`/`.desc()`/`.sort(dir)` on it, or a `sort_key(..)`",
169    note = "a `SortKey` also has to have been discharged against *this* scope — a scope lists its tables most-recently-joined first, so two that look alike can still differ in order"
170)]
171pub trait SortBy<Scope, Idxs> {
172    #[doc(hidden)]
173    fn into_sort_key(self) -> SortKey<Scope>;
174}
175
176impl<Scope: Superset<Req, Idxs>, Req, Idxs> SortBy<Scope, Idxs> for OrderKey<Req> {
177    fn into_sort_key(self) -> SortKey<Scope> {
178        SortKey {
179            kind: self.kind,
180            dir: self.dir,
181            _marker: PhantomData,
182        }
183    }
184}
185
186impl<Scope> SortBy<Scope, ()> for SortKey<Scope> {
187    fn into_sort_key(self) -> SortKey<Scope> {
188        self
189    }
190}
191
192/// The same for `GROUP BY`: an expression this scope covers, or a
193/// `grouping(..)` already discharged against it.
194#[diagnostic::on_unimplemented(
195    message = "`{Self}` isn't a grouping key",
196    label = "a column or expression, or a `grouping(..)`",
197    note = "a `Grouping` also has to have been discharged against *this* scope — a scope lists its tables most-recently-joined first, so two that look alike can still differ in order"
198)]
199pub trait GroupBy<Scope, Idxs> {
200    #[doc(hidden)]
201    fn into_grouping(self) -> Grouping<Scope>;
202}
203
204impl<Scope: Superset<Req, Idxs>, Req, Idxs, T: IntoExpr<Req = Req>> GroupBy<Scope, Idxs> for T {
205    fn into_grouping(self) -> Grouping<Scope> {
206        Grouping {
207            kind: self.into_expr().kind,
208            _marker: PhantomData,
209        }
210    }
211}
212
213impl<Scope> GroupBy<Scope, ()> for Grouping<Scope> {
214    fn into_grouping(self) -> Grouping<Scope> {
215        self
216    }
217}
218
219/// A sort key whose scope requirement has already been discharged, so a
220/// runtime-length collection of them can be built and passed around — the
221/// `?sort=email,-placed_on` case. `select::sort_key` is to `.order_by_all`
222/// what `predicate` is to `.filter_all`.
223pub struct SortKey<Scope> {
224    kind: ExprKind,
225    dir: SortDir,
226    _marker: PhantomData<fn() -> Scope>,
227}
228
229impl<Scope> Clone for SortKey<Scope> {
230    fn clone(&self) -> Self {
231        SortKey {
232            kind: self.kind.clone(),
233            dir: self.dir,
234            _marker: PhantomData,
235        }
236    }
237}
238
239/// Discharges a sort key's scope requirement. `Scope` is inferred from the
240/// query the keys are eventually given to. Takes whatever `.order_by` takes,
241/// as `predicate` takes whatever `.filter` does — so a helper generic over
242/// `SortBy` can discharge without knowing which of the two it was handed.
243pub fn sort_key<Scope, Idxs, K: SortBy<Scope, Idxs>>(key: K) -> SortKey<Scope> {
244    key.into_sort_key()
245}
246
247/// A grouping key with its scope requirement discharged — `predicate`'s
248/// counterpart for `GROUP BY`.
249pub struct Grouping<Scope> {
250    kind: ExprKind,
251    _marker: PhantomData<fn() -> Scope>,
252}
253
254impl<Scope> Clone for Grouping<Scope> {
255    fn clone(&self) -> Self {
256        Grouping {
257            kind: self.kind.clone(),
258            _marker: PhantomData,
259        }
260    }
261}
262
263/// Discharges a grouping key's scope requirement, taking whatever
264/// `.group_by` takes — the same shape `predicate` and `sort_key` have.
265pub fn grouping<Scope, Idxs, K: GroupBy<Scope, Idxs>>(key: K) -> Grouping<Scope> {
266    key.into_grouping()
267}
268
269/// Something a query can be filtered by: an `Expr` whose tables this scope
270/// contains, or a `Predicate` already discharged against it. One `.filter`
271/// for both, so which one a condition happens to be doesn't change how it is
272/// applied.
273#[diagnostic::on_unimplemented(
274    message = "`{Self}` isn't a condition",
275    label = "a comparison (`.eq(..)`, `.gt(..)`, `.is_null()`), an `any_of`/`all_of` of them, a `sql!` fragment of type `Bool`, a `predicate(..)`, or an `EXISTS`/`.contains(..)` of a subquery in *this* dialect",
276    note = "a `Predicate` also has to have been discharged against *this* scope — a scope lists its tables most-recently-joined first, so two that look alike can still differ in order"
277)]
278pub trait Condition<D, Scope, Idxs> {
279    /// Discharged against this scope, which for an `Expr` is where its
280    /// `Superset` proof is spent and for a `Predicate` already happened.
281    #[doc(hidden)]
282    fn into_predicate(self) -> Predicate<D, Scope>;
283}
284
285impl<D, Scope: Superset<Req, Idxs>, Req, Idxs, T: IntoExpr<Req = Req>> Condition<D, Scope, Idxs>
286    for T
287where
288    T::Sql: BoolLike,
289{
290    fn into_predicate(self) -> Predicate<D, Scope> {
291        Predicate {
292            kind: self.into_expr().kind,
293            _marker: PhantomData,
294        }
295    }
296}
297
298impl<D, Scope> Condition<D, Scope, ()> for Predicate<D, Scope> {
299    fn into_predicate(self) -> Predicate<D, Scope> {
300        self
301    }
302}
303
304/// `EXISTS (<subquery>)`. Not an `Expr`, because unlike every other
305/// expression this one is dialect-pinned: the subquery it holds was
306/// capability-checked against its own dialect, and any CTE it binds is
307/// already rendered in that dialect. It is therefore a condition and only a
308/// condition — `.filter(..)` it, or `predicate(..)` it into a collection,
309/// onto a query of the same dialect. A `Predicate` carries `D` for this
310/// reason: discharging a condition gives up the tables it named, never the
311/// dialect it was built for.
312pub struct Exists<D, Req> {
313    kind: ExprKind,
314    _marker: PhantomData<fn() -> (D, Req)>,
315}
316
317// Hand-written for the reason `Expr`'s is: `#[derive(Clone)]` would ask the
318// phantom tags to be `Clone`.
319impl<D, Req> Clone for Exists<D, Req> {
320    fn clone(&self) -> Self {
321        Exists {
322            kind: self.kind.clone(),
323            _marker: PhantomData,
324        }
325    }
326}
327
328impl<D, Scope: Superset<Req, Idxs>, Req, Idxs> Condition<D, Scope, Idxs> for Exists<D, Req> {
329    fn into_predicate(self) -> Predicate<D, Scope> {
330        Predicate {
331            kind: self.kind,
332            _marker: PhantomData,
333        }
334    }
335}
336
337/// `lhs IN (<subquery>)` / `lhs NOT IN (<subquery>)`. Not an `Expr`, for the
338/// same reason `Exists` isn't: the subquery it holds was capability-checked
339/// against its own dialect. `.filter(..)` it, or `predicate(..)` it into a
340/// collection, onto a query of the same dialect.
341pub struct InSubquery<D, Req> {
342    kind: ExprKind,
343    _marker: PhantomData<fn() -> (D, Req)>,
344}
345
346impl<D, Req> Clone for InSubquery<D, Req> {
347    fn clone(&self) -> Self {
348        InSubquery {
349            kind: self.kind.clone(),
350            _marker: PhantomData,
351        }
352    }
353}
354
355impl<D, Scope: Superset<Req, Idxs>, Req, Idxs> Condition<D, Scope, Idxs> for InSubquery<D, Req> {
356    fn into_predicate(self) -> Predicate<D, Scope> {
357        Predicate {
358            kind: self.kind,
359            _marker: PhantomData,
360        }
361    }
362}
363
364/// A condition whose scope requirement has already been discharged, so a
365/// runtime-length collection of them can be built and passed around. An
366/// `Expr` carries the tables it references in its type, which is what makes
367/// `vec![users_cond, orders_cond]` fail to unify; `predicate` trades that
368/// tag for a proof against one concrete scope.
369pub struct Predicate<D, Scope> {
370    kind: ExprKind,
371    _marker: PhantomData<fn() -> (D, Scope)>,
372}
373
374// Hand-written for the reason `Expr`'s is: `#[derive(Clone)]` would ask a
375// phantom `Scope` to be `Clone`.
376impl<D, Scope> Clone for Predicate<D, Scope> {
377    fn clone(&self) -> Self {
378        Predicate {
379            kind: self.kind.clone(),
380            _marker: PhantomData,
381        }
382    }
383}
384
385impl<D, Scope> Predicate<D, Scope> {
386    /// True when any of them is. `expr::any_of` combines conditions that
387    /// reference the same tables; this one combines conditions whose scope
388    /// requirement is already discharged, which is what lets a search form
389    /// OR together conditions from different tables.
390    pub fn any_of(preds: impl IntoIterator<Item = Predicate<D, Scope>>) -> Self {
391        Predicate::combine(preds, false)
392    }
393
394    /// True when all of them are — the AND to `any_of`'s OR, so a group of
395    /// them can be nested inside one.
396    pub fn all_of(preds: impl IntoIterator<Item = Predicate<D, Scope>>) -> Self {
397        Predicate::combine(preds, true)
398    }
399
400    fn combine(preds: impl IntoIterator<Item = Predicate<D, Scope>>, all: bool) -> Self {
401        Predicate {
402            kind: crate::expr::fold_conditions(preds.into_iter().map(Predicate::into_kind), all),
403            _marker: PhantomData,
404        }
405    }
406
407    pub(crate) fn into_kind(self) -> ExprKind {
408        self.kind
409    }
410}
411
412/// Discharges a condition's scope requirement, so a runtime-length
413/// collection of them can be built and passed around. `Scope` and `D` are
414/// inferred from the query the resulting predicates are eventually given to.
415pub fn predicate<D, Scope, Idxs, C: Condition<D, Scope, Idxs>>(cond: C) -> Predicate<D, Scope> {
416    cond.into_predicate()
417}
418
419/// Holds just the `SELECT` list until `.from(..)` supplies the first table
420/// and therefore the query's initial `Scope`. Splitting this out (rather
421/// than requiring `Scope` be known at `.select(..)` time) is what lets the
422/// builder read in `SELECT -> FROM -> ...` order while still validating
423/// every selected column against the *final* scope only once, at the
424/// query's terminal method (`.to_sql(Postgres)`/`.load()`).
425pub struct SelectSeed<Sel> {
426    selection: Sel,
427}
428
429pub fn select<Sel>(selection: Sel) -> SelectSeed<Sel> {
430    SelectSeed { selection }
431}
432
433impl<Sel> SelectSeed<Sel> {
434    /// `source` is a value, not a turbofish — a schema table's zero-sized
435    /// token (`users::Table`) or a `cte::with(..)` binding. A CTE brings its
436    /// `WITH` clause along, so it cannot be selected from unbound.
437    pub fn from<D, S: JoinSource<D>>(
438        self,
439        source: S,
440    ) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Nil>, Sel> {
441        let mut body = SelectBody::new(<S::Table as Table>::NAME);
442        body.bind(source);
443        Select {
444            body,
445            selection: self.selection,
446            _marker: PhantomData,
447        }
448    }
449}
450
451/// Every clause of a `SELECT` except the selection list, which `Select`
452/// keeps typed and `DynSelect` keeps rendered. Held whole by both, so a new
453/// clause is added here once instead of being threaded through each of them
454/// and through rendering by hand.
455#[derive(Debug, Clone)]
456pub(crate) struct SelectBody {
457    ctes: Vec<CteDef>,
458    distinct: bool,
459    from_table: &'static str,
460    joins: Vec<JoinClause>,
461    wheres: Vec<ExprKind>,
462    order_by: Vec<(ExprKind, SortDir)>,
463    group_by: Vec<ExprKind>,
464    having: Vec<ExprKind>,
465    limit: Option<RowCount>,
466    offset: Option<RowCount>,
467}
468
469impl SelectBody {
470    fn new(from_table: &'static str) -> Self {
471        SelectBody {
472            ctes: Vec::new(),
473            distinct: false,
474            from_table,
475            joins: Vec::new(),
476            wheres: Vec::new(),
477            order_by: Vec::new(),
478            group_by: Vec::new(),
479            having: Vec::new(),
480            limit: None,
481            offset: None,
482        }
483    }
484
485    /// `SELECT count(*)` over this body with its paging dropped: a total
486    /// counts the rows that match, not the page being shown.
487    ///
488    /// A query whose rows aren't one per matching row is counted by
489    /// wrapping it, selection and all, since what a page of it would show is
490    /// what has to be counted. Stated as what may be left unwrapped — plain
491    /// columns, no `GROUP BY`/`HAVING`/`DISTINCT` — rather than as a list of
492    /// what may not: an aggregate collapses the rows too, and `sql!` can
493    /// hold anything at all.
494    fn count_sql<D: Dialect>(&self, selection: &[SelectItem]) -> (String, Vec<Value>) {
495        let mut body = self.clone();
496        body.order_by.clear();
497        body.limit = None;
498        body.offset = None;
499        let one_row_each = body.group_by.is_empty()
500            && body.having.is_empty()
501            && !body.distinct
502            && selection
503                .iter()
504                .all(|item| matches!(item.kind, ExprKind::Column { .. }));
505
506        let mut sink = QuerySink::<D>::new();
507        if one_row_each {
508            body.render_into::<D>(&[crate::expr::count_item()], &mut sink);
509            return sink.finish();
510        }
511        crate::render::render_count_wrapped::<D>(&mut sink, |sink| {
512            body.render_into::<D>(selection, sink)
513        });
514        sink.finish()
515    }
516
517    /// Attaches whatever `WITH` binding a join source carries before its
518    /// table is named in a FROM or JOIN clause.
519    fn bind<D, S: JoinSource<D>>(&mut self, source: S) {
520        self.ctes.extend(source.binding());
521    }
522}
523
524/// A `SELECT`. `Outer` is the scope this query was built *against* — `Nil`
525/// for a query of its own, and the outer query's scope for one started by
526/// `.correlated(..)`, which is what lets `EXISTS` report the outer tables it
527/// references. Defaulted, so a query that isn't a subquery never spells it.
528pub struct Select<D, Scope, Sel, Outer = Nil> {
529    body: SelectBody,
530    selection: Sel,
531    _marker: PhantomData<fn() -> (D, Scope, Outer)>,
532}
533
534// Cloning is what lets one built-up query serve both a count and a page.
535impl<D, Scope, Sel: Clone, Outer> Clone for Select<D, Scope, Sel, Outer> {
536    fn clone(&self) -> Self {
537        Select {
538            body: self.body.clone(),
539            selection: self.selection.clone(),
540            _marker: PhantomData,
541        }
542    }
543}
544
545impl<D, Scope, Sel, Outer> Select<D, Scope, Sel, Outer> {
546    fn retype<NewScope>(self) -> Select<D, NewScope, Sel, Outer> {
547        Select {
548            body: self.body,
549            selection: self.selection,
550            _marker: PhantomData,
551        }
552    }
553
554    /// Swaps the selection list, keeping every clause. With `Clone`, this is
555    /// how one built-up query serves both a count and a page.
556    pub fn reselect<NewSel>(self, selection: NewSel) -> Select<D, Scope, NewSel, Outer> {
557        Select {
558            body: self.body,
559            selection,
560            _marker: PhantomData,
561        }
562    }
563
564    /// AND-folded, and callable any number of times — conditionally, in a
565    /// loop, from a helper — without changing `Self`'s type, so the most
566    /// common kind of dynamic query needs no escape hatch.
567    pub fn filter<C: Condition<D, Scope, Idxs>, Idxs>(mut self, cond: C) -> Self {
568        self.body.wheres.push(cond.into_predicate().into_kind());
569        self
570    }
571
572    /// AND-folds a runtime-length collection of already-discharged
573    /// conditions — the shape a search form has, where the conditions come
574    /// from different tables and so can't share one `Expr` type.
575    pub fn filter_all(mut self, conds: impl IntoIterator<Item = Predicate<D, Scope>>) -> Self {
576        self.body
577            .wheres
578            .extend(conds.into_iter().map(Predicate::into_kind));
579        self
580    }
581
582    pub fn order_by<K: SortBy<Scope, Idxs>, Idxs>(mut self, key: K) -> Self {
583        let key = key.into_sort_key();
584        self.body.order_by.push((key.kind, key.dir));
585        self
586    }
587
588    /// Appends a runtime-length collection of already-discharged sort keys
589    /// — the shape a `?sort=` parameter has, where the keys name different
590    /// tables and so can't share one `OrderKey` type.
591    pub fn order_by_all(mut self, keys: impl IntoIterator<Item = SortKey<Scope>>) -> Self {
592        self.body
593            .order_by
594            .extend(keys.into_iter().map(|k| (k.kind, k.dir)));
595        self
596    }
597
598    /// `.order_by(..)`, but the key also has to be in this query's
599    /// selection — `Sel::Output` has to hold it, the same `row::Field`
600    /// lookup `Row::get` and `SetOp::order_by_column` take, rather than the
601    /// key only being in scope. This is the exact rule `SELECT DISTINCT`
602    /// puts on a sort key (Postgres rejects one that isn't selected), so
603    /// pairing this with `.distinct()` leaves that rejected SQL unwritable.
604    ///
605    /// What gets rendered is the *selected* item the lookup landed on, for
606    /// the reason `SetOp::order_by_column` renders the ordinal rather than
607    /// the key it was handed: a key names a field, not an expression, and
608    /// two window functions over different frames share one. The index that
609    /// proves the lookup is the position that reads the item, so the check
610    /// and the rendered clause are one fact.
611    ///
612    /// **Known limitation**: `.reselect(..)` afterwards keeps the clause and
613    /// drops the guarantee — swap the selection before sorting by it.
614    pub fn order_by_selected<K, SelIdx, Idx, L>(mut self, _key: K, dir: SortDir) -> Self
615    where
616        K: LookupKey,
617        Sel: Selection<Scope, SelIdx, Output = Row<L>>,
618        L: RowFieldLookup<K::Key, Idx>,
619        Idx: Position,
620    {
621        let mut items = self.selection.items();
622        let item = items.remove(<Idx as Position>::POSITION as usize - 1);
623        self.body.order_by.push((item.kind, dir));
624        self
625    }
626
627    /// `.order_by_selected(..)` for a single un-tupled selection
628    /// (`select(users::email)`, not `select((users::email,))`): there is
629    /// exactly one selected column, so there is nothing to name — the same
630    /// shape `SetOp`'s single-column `.order_by(dir)` has, and the same
631    /// `.reselect(..)` caveat.
632    pub fn order_by_selection<SelIdx>(mut self, dir: SortDir) -> Self
633    where
634        Sel: Selection<Scope, SelIdx>,
635        Sel::Output: SingleColumn,
636    {
637        let item = self.selection.items().remove(0);
638        self.body.order_by.push((item.kind, dir));
639        self
640    }
641
642    /// `SELECT DISTINCT`: one row per distinct selected tuple. The natural
643    /// answer to a one-to-many join that repeats its left side, and unlike a
644    /// `GROUP BY` of the whole selection it doesn't have to be restated when
645    /// the selection changes. Idempotent — a query is distinct or it isn't.
646    ///
647    /// **Known limitation**: Postgres requires a `SELECT DISTINCT`'s sort
648    /// keys to be in its selection, and nothing here enforces that for
649    /// plain `.order_by(..)` — use `.order_by_selected(..)`/
650    /// `.order_by_selection(..)` instead, which check exactly this. `GROUP
651    /// BY` has a related but different gap: every non-aggregated selected
652    /// column has to appear in it, which is the selection-into-`GROUP BY`
653    /// direction rather than the `GROUP BY`-into-selection one
654    /// `row::Field` can check, so it stays unchecked. `count_sql` won't
655    /// show either problem, since a total drops the `ORDER BY`.
656    pub fn distinct(mut self) -> Self {
657        self.body.distinct = true;
658        self
659    }
660
661    /// Appends one grouping key; callable multiple times like `.filter()`
662    /// (each call adds a column to the `GROUP BY` list, it doesn't replace
663    /// it), for the same "dynamic composition without a type change" reason.
664    pub fn group_by<K: GroupBy<Scope, Idxs>, Idxs>(mut self, key: K) -> Self {
665        self.body.group_by.push(key.into_grouping().kind);
666        self
667    }
668
669    /// The same for a runtime-length collection of discharged grouping
670    /// keys, as `order_by_all` is to `order_by`.
671    pub fn group_by_all(mut self, keys: impl IntoIterator<Item = Grouping<Scope>>) -> Self {
672        self.body.group_by.extend(keys.into_iter().map(|g| g.kind));
673        self
674    }
675
676    /// A `WHERE`-shaped filter applied after grouping (aggregate
677    /// conditions) — AND-folded across calls exactly like `.filter()`.
678    pub fn having<C: Condition<D, Scope, Idxs>, Idxs>(mut self, cond: C) -> Self {
679        self.body.having.push(cond.into_predicate().into_kind());
680        self
681    }
682
683    /// The same for a runtime-length collection of discharged conditions,
684    /// as `filter_all` is to `filter`.
685    pub fn having_all(mut self, conds: impl IntoIterator<Item = Predicate<D, Scope>>) -> Self {
686        self.body
687            .having
688            .extend(conds.into_iter().map(Predicate::into_kind));
689        self
690    }
691
692    pub fn limit(mut self, n: impl IntoRowCount) -> Self {
693        self.body.limit = Some(n.into_row_count());
694        self
695    }
696
697    pub fn offset(mut self, n: impl IntoRowCount) -> Self {
698        self.body.offset = Some(n.into_row_count());
699        self
700    }
701
702    /// The joined table is in scope for the `ON` condition, and so is
703    /// everything already joined — the scope the condition is discharged
704    /// against is the one the join produces, not the one it started from.
705    pub fn inner_join<S: JoinSource<D>, C, Idxs>(
706        mut self,
707        source: S,
708        on: C,
709    ) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Scope>, Sel, Outer>
710    where
711        C: Condition<D, Cons<TableSlot<S::Table, NotNull>, Scope>, Idxs>,
712    {
713        self.body.bind(source);
714        self.body.joins.push(JoinClause {
715            kind: JoinKind::Inner,
716            table: <S::Table as Table>::NAME,
717            on: on.into_predicate().into_kind(),
718        });
719        self.retype()
720    }
721
722    pub fn left_join<S: JoinSource<D>, C, Idxs>(
723        mut self,
724        source: S,
725        on: C,
726    ) -> Select<D, Cons<TableSlot<S::Table, MaybeNull>, Scope>, Sel, Outer>
727    where
728        C: Condition<D, Cons<TableSlot<S::Table, MaybeNull>, Scope>, Idxs>,
729    {
730        self.body.bind(source);
731        self.body.joins.push(JoinClause {
732            kind: JoinKind::Left,
733            table: <S::Table as Table>::NAME,
734            on: on.into_predicate().into_kind(),
735        });
736        self.retype()
737    }
738
739    /// RIGHT JOIN retroactively flips every already-joined table to
740    /// nullable (`MapNullable`) before adding the new, guaranteed-present
741    /// table, mirroring Drizzle's `AppendToNullabilityMap` rule.
742    pub fn right_join<S: JoinSource<D>, C, Idxs>(
743        mut self,
744        source: S,
745        on: C,
746    ) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Scope::Output>, Sel, Outer>
747    where
748        D: SupportsRightJoin,
749        Scope: MapNullable,
750        C: Condition<D, Cons<TableSlot<S::Table, NotNull>, Scope::Output>, Idxs>,
751    {
752        self.body.bind(source);
753        self.body.joins.push(JoinClause {
754            kind: JoinKind::Right,
755            table: <S::Table as Table>::NAME,
756            on: on.into_predicate().into_kind(),
757        });
758        self.retype()
759    }
760
761    pub fn full_join<S: JoinSource<D>, C, Idxs>(
762        mut self,
763        source: S,
764        on: C,
765    ) -> Select<D, Cons<TableSlot<S::Table, MaybeNull>, Scope::Output>, Sel, Outer>
766    where
767        D: SupportsFullOuterJoin,
768        Scope: MapNullable,
769        C: Condition<D, Cons<TableSlot<S::Table, MaybeNull>, Scope::Output>, Idxs>,
770    {
771        self.body.bind(source);
772        self.body.joins.push(JoinClause {
773            kind: JoinKind::Full,
774            table: <S::Table as Table>::NAME,
775            on: on.into_predicate().into_kind(),
776        });
777        self.retype()
778    }
779}
780
781/// The terminal methods, and so only for a query of its own: a subquery
782/// (`Outer != Nil`) references its outer query's tables, and rendering one
783/// on its own would name tables that aren't in its `FROM`. It reaches SQL
784/// through `exists`/`not_exists` instead.
785impl<D: Dialect, Scope, Sel> Select<D, Scope, Sel> {
786    /// The terminal step, and the *only* point each selected column's
787    /// scope-membership is checked — proven as a side effect of
788    /// `Sel: Selection<Scope, Idx>` type-checking at all.
789    ///
790    /// The dialect is an argument rather than a turbofish, so a query that
791    /// is rendered instead of executed says which SQL it wants in the one
792    /// place that decides — and everything before it infers, the way a
793    /// table or a column does.
794    pub fn to_sql<Idx>(&self, _dialect: D) -> (String, Vec<Value>)
795    where
796        Sel: Selection<Scope, Idx>,
797    {
798        self.render_as::<Idx>()
799    }
800
801    /// How many rows this query would return, ignoring its
802    /// `ORDER BY`/`LIMIT`/`OFFSET` — a total is about what matches, not about
803    /// the page being shown. `reselect(count())` keeps them, which is what
804    /// makes it the wrong tool for a paginated total.
805    ///
806    /// A grouped query counts its *groups*, since that is what a page of it
807    /// would show, so the body becomes a subquery rather than having its
808    /// `GROUP BY` dropped or kept.
809    pub fn count_sql<Idx>(&self, _dialect: D) -> (String, Vec<Value>)
810    where
811        Sel: Selection<Scope, Idx>,
812    {
813        self.body.count_sql::<D>(&self.selection.items())
814    }
815}
816
817impl<D: Dialect, Scope, Sel> Select<D, Scope, Sel> {
818    /// This query as an embeddable `Fragment`: an `EXISTS (..)` subquery, a
819    /// CTE body, or a set-operation branch. The only way to produce one, so
820    /// no caller has to remember that an embedded query renders with `?`
821    /// placeholders rather than `D`'s own style. `Outer = Nil` like the
822    /// other terminals: a correlated subquery names tables that aren't in
823    /// its own `FROM`, and reaches SQL through `EXISTS` instead.
824    pub(crate) fn fragment<Idx>(&self) -> Fragment
825    where
826        Sel: Selection<Scope, Idx>,
827    {
828        let mut sink = FragmentSink::new();
829        self.body
830            .render_into::<D>(&self.selection.items(), &mut sink);
831        sink.finish()
832    }
833
834    fn render_as<Idx>(&self) -> (String, Vec<Value>)
835    where
836        Sel: Selection<Scope, Idx>,
837    {
838        let mut sink = QuerySink::<D>::new();
839        self.body
840            .render_into::<D>(&self.selection.items(), &mut sink);
841        sink.finish()
842    }
843}
844
845impl SelectBody {
846    pub(crate) fn render_into<D: Dialect>(&self, selection: &[SelectItem], sink: &mut dyn Sink) {
847        let SelectBody {
848            ctes,
849            distinct,
850            from_table,
851            joins,
852            wheres,
853            order_by,
854            group_by,
855            having,
856            limit,
857            offset,
858        } = self;
859
860        if !ctes.is_empty() {
861            sink.text("WITH ");
862            for (i, cte) in ctes.iter().enumerate() {
863                if i > 0 {
864                    sink.text(", ");
865                }
866                crate::render::render_ident::<D>(sink, cte.name);
867                sink.text(" (");
868                for (i, col) in cte.column_names.iter().enumerate() {
869                    if i > 0 {
870                        sink.text(", ");
871                    }
872                    crate::render::render_ident::<D>(sink, col);
873                }
874                sink.text(") AS (");
875                cte.body.splice_into(sink);
876                sink.ch(')');
877            }
878            sink.ch(' ');
879        }
880        sink.text("SELECT ");
881        if *distinct {
882            sink.text("DISTINCT ");
883        }
884
885        render_select_list::<D>(selection, sink);
886
887        sink.text(" FROM ");
888        crate::render::render_ident::<D>(sink, from_table);
889
890        for j in joins {
891            sink.ch(' ');
892            sink.text(match j.kind {
893                JoinKind::Inner => "INNER JOIN",
894                JoinKind::Left => "LEFT JOIN",
895                JoinKind::Right => "RIGHT JOIN",
896                JoinKind::Full => "FULL JOIN",
897            });
898            sink.ch(' ');
899            crate::render::render_ident::<D>(sink, j.table);
900            sink.text(" ON ");
901            render_expr::<D>(&j.on, sink);
902        }
903
904        render_and_list::<D>(sink, " WHERE ", wheres);
905
906        render_expr_list::<D>(sink, " GROUP BY ", group_by);
907        render_and_list::<D>(sink, " HAVING ", having);
908        render_order_by::<D>(sink, " ORDER BY ", order_by);
909        render_limit_offset::<D>(sink, limit.as_ref(), offset.as_ref());
910    }
911}
912
913/// Starts a correlated subquery against a scope, rather than against a
914/// query — so `UPDATE`/`DELETE`, whose scope is the one table they write,
915/// reach the same `EXISTS` a `SELECT` does without conjuring a `Select`
916/// they don't otherwise need.
917pub(crate) fn correlated_with<D, Scope, S: JoinSource<D>, InnerSel>(
918    source: S,
919    selection: InnerSel,
920) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Scope>, InnerSel, Scope> {
921    let mut body = SelectBody::new(<S::Table as Table>::NAME);
922    body.bind(source);
923    Select {
924        body,
925        selection,
926        _marker: PhantomData,
927    }
928}
929
930impl<D, Scope, Sel, Outer> Select<D, Scope, Sel, Outer> {
931    /// Starts a correlated subquery: a fresh `SELECT` whose scope is
932    /// `Cons<TableSlot<T, NotNull>, Scope>` — the new table, prepended onto
933    /// *this* (outer) query's entire scope. Because `Find`/`Superset` walk
934    /// the whole flat cons-list regardless of where it came from, the
935    /// subquery's `.filter()` can reference both its own new table's
936    /// columns and any outer column already in `Scope`, with no special
937    /// casing: growing the scope works the same whether the new table came
938    /// from a join or from a subquery's `FROM`.
939    ///
940    /// The result is an ordinary `Select` — every clause it takes is the
941    /// one `Select` already has — carrying this query's scope as its
942    /// `Outer`, which is what `exists` reports.
943    pub fn correlated<S: JoinSource<D>, InnerSel>(
944        &self,
945        source: S,
946        selection: InnerSel,
947    ) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Scope>, InnerSel, Scope> {
948        correlated_with(source, selection)
949    }
950}
951
952impl<D: Dialect, Scope, Sel, Outer: ScopeTables> Select<D, Scope, Sel, Outer> {
953    /// `EXISTS (<this query>)`, tagged with the outer tables it references
954    /// so it can only be filtered onto a query that has them in scope. Its
955    /// own column references were already checked against `Scope` when it
956    /// was built. On a query that isn't a subquery, `Outer` is `Nil` and
957    /// this is an uncorrelated `EXISTS`.
958    pub fn exists<Idx>(&self) -> Exists<D, Outer::Tables>
959    where
960        Sel: Selection<Scope, Idx>,
961    {
962        self.exists_kind::<Idx>(false)
963    }
964
965    pub fn not_exists<Idx>(&self) -> Exists<D, Outer::Tables>
966    where
967        Sel: Selection<Scope, Idx>,
968    {
969        self.exists_kind::<Idx>(true)
970    }
971
972    fn exists_kind<Idx>(&self, negated: bool) -> Exists<D, Outer::Tables>
973    where
974        Sel: Selection<Scope, Idx>,
975    {
976        Exists {
977            kind: ExprKind::Exists {
978                body: Box::new(self.body.clone()),
979                selection: self.selection.items(),
980                negated,
981            },
982            _marker: PhantomData,
983        }
984    }
985
986    /// `lhs IN (<this query>)`. This query selects exactly one column
987    /// (`Sel: RowField` — a bare column, aggregate, or labelled one of
988    /// those, never a tuple), so its SQL type can be checked against `lhs`
989    /// the same way `.eq(..)` checks two columns: `RowField::Sql` carries
990    /// the marker a decoded `Selection::Output` has already resolved away.
991    /// Tagged with the outer tables `lhs` and this query's own `Outer`
992    /// reference, so it can only be filtered onto a query that has both in
993    /// scope.
994    ///
995    /// **Known limitation**: membership only. A *scalar* subquery
996    /// (`col = (SELECT max(x) ..)`) stays deferred — it would have to be an
997    /// `Expr`, which carries no dialect to pin the subquery's capability
998    /// check to.
999    pub fn contains<Lhs, Idx>(
1000        &self,
1001        lhs: Lhs,
1002    ) -> InSubquery<D, <Outer::Tables as Concat<Lhs::Req>>::Output>
1003    where
1004        Lhs: IntoExpr,
1005        Lhs::Sql: Comparable<Sel::Sql>,
1006        Sel: RowField<Scope, Idx> + Selection<Scope, Idx>,
1007        Outer::Tables: Concat<Lhs::Req>,
1008    {
1009        self.in_subquery_kind::<Lhs, Idx>(lhs, false)
1010    }
1011
1012    pub fn not_contains<Lhs, Idx>(
1013        &self,
1014        lhs: Lhs,
1015    ) -> InSubquery<D, <Outer::Tables as Concat<Lhs::Req>>::Output>
1016    where
1017        Lhs: IntoExpr,
1018        Lhs::Sql: Comparable<Sel::Sql>,
1019        Sel: RowField<Scope, Idx> + Selection<Scope, Idx>,
1020        Outer::Tables: Concat<Lhs::Req>,
1021    {
1022        self.in_subquery_kind::<Lhs, Idx>(lhs, true)
1023    }
1024
1025    fn in_subquery_kind<Lhs, Idx>(
1026        &self,
1027        lhs: Lhs,
1028        negated: bool,
1029    ) -> InSubquery<D, <Outer::Tables as Concat<Lhs::Req>>::Output>
1030    where
1031        Lhs: IntoExpr,
1032        Lhs::Sql: Comparable<Sel::Sql>,
1033        Sel: RowField<Scope, Idx> + Selection<Scope, Idx>,
1034        Outer::Tables: Concat<Lhs::Req>,
1035    {
1036        InSubquery {
1037            kind: ExprKind::InSubquery {
1038                lhs: Box::new(lhs.into_expr().kind),
1039                body: Box::new(self.body.clone()),
1040                selection: self.selection.items(),
1041                negated,
1042            },
1043            _marker: PhantomData,
1044        }
1045    }
1046}
1047
1048/// A number of rows — what a `LIMIT` and an `OFFSET` each are: an integer,
1049/// or a `prepare!{}` placeholder for one, so a paginated endpoint can
1050/// prepare its query once and vary the page. A trait rather than
1051/// `Into<i64>` so a `usize` page size — the shape a paginated handler
1052/// already has — goes in without a cast. Every numeric impl lands in
1053/// `0..=i64::MAX`: a negative count is not a query any database will run,
1054/// and a `usize` past `i64::MAX` is not a page anyone is asking for.
1055#[diagnostic::on_unimplemented(
1056    message = "`{Self}` isn't a number of rows",
1057    label = "an integer, or a `prepare!{{}}` placeholder of type `Integer`/`BigInt`"
1058)]
1059pub trait IntoRowCount {
1060    fn into_row_count(self) -> RowCount;
1061}
1062
1063/// What a `LIMIT`/`OFFSET` clause holds. Opaque: the `IntoRowCount` impls
1064/// are the only way to make one.
1065#[derive(Debug, Clone)]
1066pub struct RowCount(RowCountKind);
1067
1068#[derive(Debug, Clone)]
1069enum RowCountKind {
1070    /// Written into the SQL text: a page size is not a value the plan
1071    /// should be reused across.
1072    Literal(i64),
1073    /// A bound parameter, which is what a `prepare!{}` placeholder is.
1074    Bound(ExprKind),
1075}
1076
1077macro_rules! into_row_count {
1078    ($($signed:ty),+ ; $($unsigned:ty),+) => {
1079        $(impl IntoRowCount for $signed {
1080            fn into_row_count(self) -> RowCount {
1081                RowCount(RowCountKind::Literal((self as i64).max(0)))
1082            }
1083        })+
1084        $(impl IntoRowCount for $unsigned {
1085            fn into_row_count(self) -> RowCount {
1086                RowCount(RowCountKind::Literal(i64::try_from(self).unwrap_or(i64::MAX)))
1087            }
1088        })+
1089    };
1090}
1091into_row_count!(i8, i16, i32, i64, isize ; u8, u16, u32, u64, usize);
1092
1093/// A `prepare!{}` placeholder, or any other scope-free `Expr` of an integer type:
1094/// bound rather than written, so one prepared query serves every page. Only
1095/// the two integer types — a page is a number.
1096impl IntoRowCount for Expr<Nil, crate::expr::Integer> {
1097    fn into_row_count(self) -> RowCount {
1098        RowCount(RowCountKind::Bound(self.kind))
1099    }
1100}
1101
1102impl IntoRowCount for Expr<Nil, crate::expr::BigInt> {
1103    fn into_row_count(self) -> RowCount {
1104        RowCount(RowCountKind::Bound(self.kind))
1105    }
1106}
1107
1108/// `LIMIT`/`OFFSET`, with the filler a dialect needs when there's an offset
1109/// and no limit — a bare `OFFSET` is Postgres-only.
1110pub(crate) fn render_limit_offset<D: Dialect>(
1111    sink: &mut dyn Sink,
1112    limit: Option<&RowCount>,
1113    offset: Option<&RowCount>,
1114) {
1115    match (limit, offset, D::OFFSET_WITHOUT_LIMIT) {
1116        (Some(l), _, _) => {
1117            sink.text(" LIMIT ");
1118            render_row_count::<D>(sink, l);
1119        }
1120        (None, Some(_), Some(filler)) => {
1121            sink.text(" LIMIT ");
1122            sink.text(filler);
1123        }
1124        _ => {}
1125    }
1126    if let Some(o) = offset {
1127        sink.text(" OFFSET ");
1128        render_row_count::<D>(sink, o);
1129    }
1130}
1131
1132fn render_row_count<D: Dialect>(sink: &mut dyn Sink, count: &RowCount) {
1133    match &count.0 {
1134        RowCountKind::Literal(n) => sink.text(&n.to_string()),
1135        RowCountKind::Bound(kind) => render_expr::<D>(kind, sink),
1136    }
1137}