Skip to main content

qbrs_core/select/
selection.rs

1//! What a `.select(..)` list decodes to once a row comes back.
2
3use crate::expr::{Column, ColumnKey, ExprKind, Keyed, LabelKey, Labeled, SqlType};
4use crate::render::SelectItem;
5use std::marker::PhantomData;
6
7use crate::row::{Named, Row, RowCons, RowKey, RowNil};
8use crate::scope::{Find, Superset, Table, WrapNullable};
9
10/// Sealed for the reason `InsertRow` is: these traits pair a type-level
11/// claim (`Fields`/`Output`) with the runtime list of `SelectItem`s that is
12/// supposed to match it, and only the impls in this crate keep the two in
13/// step. A hand-written one could select a row that decodes transposed —
14/// the failure `row::SameShape` and column-keyed rows exist to stop.
15mod private {
16    /// Carries the trait's own parameters, for the reason `scope::proof`
17    /// explains: `Self` can be an honest `Column<C>` while the free `Idx`
18    /// is the caller's own type, so a seal on `Self` alone admits the
19    /// forgery — and a private proof *type* is reachable by projection.
20    pub trait Sealed<Scope, Idx> {}
21}
22
23/// `AllColumns`/`CteShape` are emitted in the schema's own crate, so their
24/// seal has to be nameable there — a separate trait, because sharing
25/// `private::Sealed` would hand out the one line that unseals `Selection`
26/// too, and a hand-written `Selection` is exactly what the seal is for.
27#[doc(hidden)]
28pub trait SelectableSealed {}
29
30impl<C, Scope, Idx> private::Sealed<Scope, Idx> for Column<C>
31where
32    C: crate::expr::ColumnKey,
33    Scope: Find<C::Table, Idx>,
34{
35}
36
37impl<K, Req, S: SqlType, Scope, Idx> private::Sealed<Scope, Idx> for Keyed<K, Req, S> where
38    Scope: Superset<Req, Idx>
39{
40}
41
42impl<K, Inner, Scope, Idx> private::Sealed<Scope, Idx> for Labeled<K, Inner> where
43    Inner: RowField<Scope, Idx>
44{
45}
46
47impl<T: AllColumns, Scope, Idx> private::Sealed<Scope, Idx> for All<T> where
48    T::Columns: ColumnList<Scope, Idx>
49{
50}
51
52/// What a single un-tupled selection decodes to: a bare native value, or
53/// its `Option`. Sealed by construction — the impls come from the same
54/// `sql_leaf_type!` that declares the types — and used to give a
55/// one-column set operation an `ORDER BY` with no position to state.
56pub trait SingleColumn {}
57
58/// One *field* of a resulting `Row`: the key its value is filed under, and
59/// the Rust type it decodes to. A selection list is a chain of
60/// `SelectionPart`s, one of which — `All` — carries many of these at once.
61///
62/// Parameterized by `Scope` so a bare column's `Value` is `Option<T>` when —
63/// and only when — that column's table is nullable in *this* query, via
64/// `scope::Find::Nullability` + `WrapNullable`. Nullability is therefore
65/// derived from join shape rather than asserted with a manual `.nullable()`.
66///
67/// Scope membership is proven as a side effect of this trait type-checking
68/// at all, through the `Find`/`Superset` bounds below — so callers need no
69/// separate check.
70#[diagnostic::on_unimplemented(
71    message = "`{Self}` can't be a field of this query's rows",
72    label = "a column, an aggregate, a window function, a `sql!` fragment, or a labelled one of those can be",
73    note = "an expression the builder inferred a type for — a comparison, an `is_null`, a `LIKE` — has to state what it decodes to with `.decodes_as::<..>()`, since that inference can contradict the join; a `sql!` fragment already states it"
74)]
75pub trait RowField<Scope, Idx>: RowKey + private::Sealed<Scope, Idx> {
76    type Value;
77    fn item(&self) -> SelectItem;
78}
79
80impl<C: ColumnKey, Scope, Idx> RowField<Scope, Idx> for Column<C>
81where
82    Scope: Find<C::Table, Idx>,
83    C::Sql: WrapNullable<<Scope as Find<C::Table, Idx>>::Nullability>,
84    <C::Sql as WrapNullable<<Scope as Find<C::Table, Idx>>::Nullability>>::Output: SqlType,
85{
86    type Value = <<C::Sql as WrapNullable<
87        <Scope as Find<C::Table, Idx>>::Nullability,
88    >>::Output as SqlType>::Native;
89    fn item(&self) -> SelectItem {
90        SelectItem::bare(ExprKind::Column {
91            table: <C::Table as Table>::NAME,
92            name: C::NAME,
93        })
94    }
95}
96
97impl<K, Req, S: SqlType, Scope, Idx> RowField<Scope, Idx> for Keyed<K, Req, S>
98where
99    Scope: Superset<Req, Idx>,
100{
101    type Value = S::Native;
102    fn item(&self) -> SelectItem {
103        SelectItem::bare(self.kind.clone())
104    }
105}
106
107/// A label renames whatever it wraps and changes nothing else, so this is
108/// one impl rather than one per selectable: the inner value decides the
109/// scope check and the decoded type, the label decides the `AS` and the row
110/// key.
111impl<K: LabelKey, Inner: RowField<Scope, Idx>, Scope, Idx> RowField<Scope, Idx>
112    for Labeled<K, Inner>
113{
114    type Value = Inner::Value;
115    fn item(&self) -> SelectItem {
116        SelectItem::labeled(self.inner.item().kind, <K as Named>::NAME)
117    }
118}
119
120/// A whole `SELECT` list. A tuple decodes to a `row::Row` keyed by each
121/// element's `RowField::Key`; a single un-tupled element decodes to its bare
122/// value, since there is nothing to key it against.
123#[diagnostic::on_unimplemented(
124    message = "`{Self}` isn't a valid selection list here",
125    label = "a selection is a column, an aggregate, a window function, a `sql!` fragment, a labelled one of those, `<table>::All`, or a tuple of up to 16 of them",
126    note = "every element has to be in scope — `.from(..)`/`.join(..)` the tables it names — and an expression the builder inferred a type for has to state its decoded type with `.decodes_as::<..>()`"
127)]
128pub trait Selection<Scope, Idx>: private::Sealed<Scope, Idx> {
129    type Output;
130    fn items(&self) -> Vec<SelectItem>;
131}
132
133macro_rules! scalar_selection {
134    (impl[$($generics:tt)*] $ty:ty) => {
135        impl<$($generics)*, Scope, Idx> Selection<Scope, Idx> for $ty
136        where
137            $ty: RowField<Scope, Idx>,
138        {
139                    type Output = <$ty as RowField<Scope, Idx>>::Value;
140            fn items(&self) -> Vec<SelectItem> {
141                vec![RowField::item(self)]
142            }
143        }
144    };
145}
146
147/// One element of a selection list. A column or an expression contributes
148/// one field; `All` contributes a whole table's worth. `Fields<Tail>` is
149/// what it puts in front of whatever the rest of the list contributes, so a
150/// list is assembled by nesting rather than by concatenating afterwards.
151#[diagnostic::on_unimplemented(
152    message = "`{Self}` can't be part of a selection list",
153    label = "a column, an aggregate, a window function, a `sql!` fragment, a labelled one of those, or `<table>::All` can be",
154    note = "an expression the builder inferred a type for — a comparison, an `is_null`, a `LIKE` — has to state what it decodes to with `.decodes_as::<..>()`, since that inference can contradict the join"
155)]
156pub trait SelectionPart<Scope, Idx>: private::Sealed<Scope, Idx> {
157    type Fields<Tail>;
158    fn push_items(&self, out: &mut Vec<SelectItem>);
159}
160
161macro_rules! field_part {
162    (impl[$($generics:tt)*] $ty:ty) => {
163        impl<$($generics)*, Scope, Idx> SelectionPart<Scope, Idx> for $ty
164        where
165            $ty: RowField<Scope, Idx>,
166        {
167                    type Fields<Tail> = RowCons<
168                <$ty as RowKey>::Key,
169                <$ty as RowField<Scope, Idx>>::Value,
170                Tail,
171            >;
172            fn push_items(&self, out: &mut Vec<SelectItem>) {
173                out.push(RowField::item(self));
174            }
175        }
176    };
177}
178/// Everything selectable on its own: as a whole list of one, and as one
179/// part of a longer list. Stated once, since a selectable that is one and
180/// not the other has never been a thing.
181macro_rules! selectable {
182    (impl[$($generics:tt)*] $ty:ty) => {
183        scalar_selection!(impl[$($generics)*] $ty);
184        field_part!(impl[$($generics)*] $ty);
185    };
186}
187selectable!(impl[C: ColumnKey] Column<C>);
188selectable!(impl[K, Req, S: SqlType] Keyed<K, Req, S>);
189selectable!(impl[K, Inner] Labeled<K, Inner>);
190
191/// Every column of one table, in declaration order — `select(users::All)`.
192/// The table's own `#[derive(Table)]` supplies the chain through
193/// `AllColumns`, so a selection list and the schema cannot drift apart, and
194/// a whole table counts as one element of a tuple however many columns it
195/// has.
196pub struct All<T>(PhantomData<fn() -> T>);
197
198impl<T> All<T> {
199    pub const fn new() -> Self {
200        All(PhantomData)
201    }
202}
203
204impl<T> Clone for All<T> {
205    fn clone(&self) -> Self {
206        *self
207    }
208}
209impl<T> Copy for All<T> {}
210
211impl<T> Default for All<T> {
212    fn default() -> Self {
213        All::new()
214    }
215}
216
217/// What `#[derive(Table)]` emits so `All<Table>` knows the table's columns
218/// and what each of them decodes to in a given scope.
219pub trait AllColumns: SelectableSealed {
220    /// The table's columns as a type-level list, `Cons<Column<C>, ..>`.
221    /// The row and the rendered items are both computed from it here, so a
222    /// hand-written impl can name a different set of columns but can never
223    /// make the two disagree — which is what a schema's own crate could do
224    /// while this trait stated the row and pushed the items separately.
225    type Columns;
226}
227
228/// The list `AllColumns` names, walked once for the row's fields and once
229/// for the items. Implemented for `Nil` and `Cons<Column<C>, Tail>` only,
230/// and only here — sealed, because this trait *is* the pairing `AllColumns`
231/// was split up to remove: it states the row and pushes the items
232/// separately, so a hand-written impl could transpose them. Nothing outside
233/// this crate implements it, so an ordinary private supertrait is enough;
234/// no `Proof` is needed.
235mod column_list {
236    pub trait Sealed {}
237    impl Sealed for crate::scope::Nil {}
238    impl<C: crate::expr::ColumnKey, Tail> Sealed for crate::scope::Cons<crate::expr::Column<C>, Tail> {}
239}
240
241pub trait ColumnList<Scope, Idx>: column_list::Sealed {
242    type Fields<Tail>;
243    fn push_items(out: &mut Vec<SelectItem>);
244}
245
246impl<Scope, Idx> ColumnList<Scope, Idx> for crate::scope::Nil {
247    type Fields<Tail> = Tail;
248    fn push_items(_out: &mut Vec<SelectItem>) {}
249}
250
251impl<C: ColumnKey, Tail, Scope, Idx> ColumnList<Scope, Idx> for crate::scope::Cons<Column<C>, Tail>
252where
253    Column<C>: RowField<Scope, Idx>,
254    Tail: ColumnList<Scope, Idx>,
255{
256    type Fields<T> = RowCons<C, <Column<C> as RowField<Scope, Idx>>::Value, Tail::Fields<T>>;
257    fn push_items(out: &mut Vec<SelectItem>) {
258        out.push(RowField::item(&Column::<C>::new()));
259        Tail::push_items(out);
260    }
261}
262
263impl<T: AllColumns, Scope, Idx> SelectionPart<Scope, Idx> for All<T>
264where
265    T::Columns: ColumnList<Scope, Idx>,
266{
267    type Fields<Tail> = <T::Columns as ColumnList<Scope, Idx>>::Fields<Tail>;
268    fn push_items(&self, out: &mut Vec<SelectItem>) {
269        <T::Columns as ColumnList<Scope, Idx>>::push_items(out);
270    }
271}
272
273impl<T: AllColumns, Scope, Idx> Selection<Scope, Idx> for All<T>
274where
275    T::Columns: ColumnList<Scope, Idx>,
276{
277    type Output = Row<<T::Columns as ColumnList<Scope, Idx>>::Fields<RowNil>>;
278    fn items(&self) -> Vec<SelectItem> {
279        let mut out = Vec::new();
280        <T::Columns as ColumnList<Scope, Idx>>::push_items(&mut out);
281        out
282    }
283}
284
285macro_rules! row_chain {
286    ($n:ident $i:ident) => {
287        <$n as SelectionPart<Scope, $i>>::Fields<RowNil>
288    };
289    ($n:ident $i:ident, $($rest:tt)*) => {
290        <$n as SelectionPart<Scope, $i>>::Fields<row_chain!($($rest)*)>
291    };
292}
293
294macro_rules! tuple_selection {
295    ($($n:ident $i:ident),+) => {
296        impl<Scope, $($n,)+ $($i,)+> private::Sealed<Scope, ($($i,)+)> for ($($n,)+)
297        where
298            $($n: SelectionPart<Scope, $i>,)+
299        {
300        }
301
302        #[allow(non_snake_case)]
303        impl<Scope, $($n,)+ $($i,)+> Selection<Scope, ($($i,)+)> for ($($n,)+)
304        where
305            $($n: SelectionPart<Scope, $i>,)+
306        {
307                    type Output = Row<row_chain!($($n $i),+)>;
308            fn items(&self) -> Vec<SelectItem> {
309                let ($($n,)+) = self;
310                let mut out = Vec::new();
311                $(SelectionPart::push_items($n, &mut out);)+
312                out
313            }
314        }
315    };
316}
317tuple_selection!(A IA);
318tuple_selection!(A IA, B IB);
319tuple_selection!(A IA, B IB, C IC);
320tuple_selection!(A IA, B IB, C IC, D ID);
321tuple_selection!(A IA, B IB, C IC, D ID, E IE);
322tuple_selection!(A IA, B IB, C IC, D ID, E IE, F IF);
323tuple_selection!(A IA, B IB, C IC, D ID, E IE, F IF, G IG);
324tuple_selection!(A IA, B IB, C IC, D ID, E IE, F IF, G IG, H IH);
325tuple_selection!(A IA, B IB, C IC, D ID, E IE, F IF, G IG, H IH, I II);
326tuple_selection!(A IA, B IB, C IC, D ID, E IE, F IF, G IG, H IH, I II, J IJ);
327tuple_selection!(A IA, B IB, C IC, D ID, E IE, F IF, G IG, H IH, I II, J IJ, K IK);
328tuple_selection!(A IA, B IB, C IC, D ID, E IE, F IF, G IG, H IH, I II, J IJ, K IK, L IL);
329tuple_selection!(A IA, B IB, C IC, D ID, E IE, F IF, G IG, H IH, I II, J IJ, K IK, L IL, M IM);
330tuple_selection!(A IA, B IB, C IC, D ID, E IE, F IF, G IG, H IH, I II, J IJ, K IK, L IL, M IM, N IN);
331tuple_selection!(A IA, B IB, C IC, D ID, E IE, F IF, G IG, H IH, I II, J IJ, K IK, L IL, M IM, N IN, O IO);
332tuple_selection!(A IA, B IB, C IC, D ID, E IE, F IF, G IG, H IH, I II, J IJ, K IK, L IL, M IM, N IN, O IO, P IP);