Skip to main content

drizzle_core/row/
mod.rs

1//! Row type inference and row decoding for SELECT queries.
2//!
3//! These traits work out the Rust type a query returns from what it selects,
4//! its table, and its joins, so `.all()` and `.get()` need no turbofish. They
5//! also decode database rows into that type.
6//!
7//! Most of this is internal machinery driven by the builders and the table
8//! macros. Users meet it through compile errors at `.all()` / `.get()` /
9//! `.rows()`, for example when a column from a `LEFT JOIN` is decoded as `T`
10//! instead of `Option<T>`.
11//!
12//! # How a row type is built
13//!
14//! ```text
15//! .select(cols)  -> marker  (SelectStar | SelectCols<C> | SelectExpr | SelectAs<R>)   via IntoSelectTarget
16//! .from(table)   -> R       (marker + table -> row type)                              via ResolveRow
17//! .join(t2)      -> R'      (marker + R + joined table -> new row type)               via JoinStep
18//! .all()         -> Vec<R>  (scope, GROUP BY and decode checks, then FromDrizzleRow)
19//! ```
20//!
21//! # Checks at the terminal method
22//!
23//! - [`MarkerScopeValidFor`]: every table the query reads was added with
24//!   `.from(...)` or a join (see [`crate::scope`]).
25//! - [`MarkerAggValidFor`]: with GROUP BY, every non-aggregate selected
26//!   column is grouped.
27//! - [`MarkerColumnCountValid`]: the decode target matches the selected
28//!   columns, with `Option` wherever an outer join can produce NULL.
29//! - [`StrictDecodeMarker`]: a raw `sql!` projection has an explicit type.
30
31// Driver-specific leaf FromDrizzleRow implementations
32#[cfg(feature = "libsql")]
33mod libsql;
34#[cfg(any(feature = "tokio-postgres", feature = "postgres-sync"))]
35mod postgres;
36#[cfg(feature = "rusqlite")]
37mod rusqlite;
38// Shared blanket impls for SQLite-flavored drivers whose cells are tagged
39// unions (rusqlite, libsql, turso). The driver-specific files above just
40// impl `SqliteValueRow` for their row type; everything else lives here.
41#[cfg(any(feature = "rusqlite", feature = "libsql", feature = "turso"))]
42pub(crate) mod sqlite_value;
43#[cfg(feature = "turso")]
44mod turso;
45
46use core::marker::PhantomData;
47
48use crate::error::DrizzleError;
49use crate::{Cons, Nil};
50
51// =============================================================================
52// Select Target Markers
53// =============================================================================
54
55/// Select marker for `SELECT *`: the row type is the table's select model and
56/// grows with each join.
57#[derive(Debug, Clone, Copy, Default)]
58pub struct SelectStar;
59
60/// Select marker for explicit columns: the row type is a tuple of the
61/// columns' value types and does not change with joins.
62#[derive(Debug, Clone, Copy, Default)]
63pub struct SelectCols<Cols>(PhantomData<Cols>);
64
65/// Select marker for raw SQL or an untyped expression: the caller must name
66/// the row type.
67#[derive(Debug, Clone, Copy, Default)]
68pub struct SelectExpr;
69
70/// Select marker for a user-chosen row model `R`, such as a `FromRow` struct
71/// passed as `.select(MyRow::Select)`.
72#[derive(Debug, Clone, Copy, Default)]
73pub struct SelectAs<R>(PhantomData<R>);
74
75pub use crate::scope::{
76    HasScope, OuterJoined, ScopeContains, ScopeEntry, ScopeHere, ScopeThere, Scoped,
77};
78
79/// The query only reads tables it has added with `.from(...)` or a join.
80///
81/// `.all()`, `.get()` and `.rows()` require this bound. It holds when:
82///
83/// - every source read by a clause (JOIN ON, WHERE, GROUP BY, HAVING,
84///   ORDER BY) is in the query's scope;
85/// - every explicitly selected column comes from a source in scope;
86/// - a `FromRow` selector's tables are in scope, and every field it reads
87///   from the nullable side of an outer join is an `Option`.
88///
89/// A failure is reported through the trait that failed underneath, most
90/// often "`X` is not in this query's FROM/JOIN scope" (see
91/// [`crate::scope`]). `Proof` is a witness type the compiler infers.
92///
93/// # Compile-time checks
94///
95/// A `FromRow` model reading `Users` passes when `Users` is in scope:
96///
97/// ```
98/// use drizzle_core::{Cons, Nil, Scoped, SelectAs, SelectTableFields, TableFields};
99/// use drizzle_core::scope::{ScopeEntry, TableKey, name::{H1, H2}};
100/// use drizzle_core::expr::NonNull;
101/// use drizzle_core::row::MarkerScopeValidFor;
102///
103/// struct Users;
104/// impl ScopeEntry for Users {
105///     type Key = TableKey<Cons<H1, Nil>, Users>;
106///     type Nullable = NonNull;
107///     type Sources = ();
108/// }
109/// struct Model;
110/// impl SelectTableFields for Model {
111///     type TableFields = Cons<TableFields<Users, Cons<i32, Nil>>, Nil>;
112/// }
113///
114/// fn needs_valid<M: MarkerScopeValidFor<P>, P>() {}
115///
116/// fn main() {
117///     needs_valid::<Scoped<SelectAs<Model>, Cons<Users, Nil>>, _>();
118/// }
119/// ```
120///
121/// It fails when the query only selects from `Posts`:
122///
123/// ```compile_fail
124/// use drizzle_core::{Cons, Nil, Scoped, SelectAs, SelectTableFields, TableFields};
125/// use drizzle_core::scope::{ScopeEntry, TableKey, name::{H1, H2}};
126/// use drizzle_core::expr::NonNull;
127/// use drizzle_core::row::MarkerScopeValidFor;
128///
129/// struct Users;
130/// struct Posts;
131/// impl ScopeEntry for Users {
132///     type Key = TableKey<Cons<H1, Nil>, Users>;
133///     type Nullable = NonNull;
134///     type Sources = ();
135/// }
136/// impl ScopeEntry for Posts {
137///     type Key = TableKey<Cons<H2, Nil>, Posts>;
138///     type Nullable = NonNull;
139///     type Sources = ();
140/// }
141/// struct Model;
142/// impl SelectTableFields for Model {
143///     type TableFields = Cons<TableFields<Users, Cons<i32, Nil>>, Nil>;
144/// }
145///
146/// fn needs_valid<M: MarkerScopeValidFor<P>, P>() {}
147///
148/// fn main() {
149///     needs_valid::<Scoped<SelectAs<Model>, Cons<Posts, Nil>>, _>();
150/// }
151/// ```
152pub trait MarkerScopeValidFor<Proof> {}
153
154impl<Scope, Used, Proof> MarkerScopeValidFor<Proof> for Scoped<SelectStar, Scope, Used> where
155    Used: SourcesIn<Nil, Proof>
156{
157}
158
159impl<Scope, Used, Proof> MarkerScopeValidFor<Proof> for Scoped<SelectExpr, Scope, Used> where
160    Used: SourcesIn<Nil, Proof>
161{
162}
163
164impl<R, Scope, Used, UsedProof, FieldsProof> MarkerScopeValidFor<(UsedProof, FieldsProof)>
165    for Scoped<SelectAs<R>, Scope, Used>
166where
167    Used: SourcesIn<Nil, UsedProof>,
168    R: SelectTableFields,
169    R::TableFields: TableFieldsIn<Scope, FieldsProof>,
170{
171}
172
173impl<Cols, Scope, Used, UsedProof, ColsProof> MarkerScopeValidFor<(UsedProof, ColsProof)>
174    for Scoped<SelectCols<Cols>, Scope, Used>
175where
176    Used: SourcesIn<Nil, UsedProof>,
177    Cols: SelectedExpressionList,
178    Cols::Expressions: ProjectionIn<Scope, ColsProof>,
179{
180}
181
182use crate::scope::SourcesIn;
183
184/// Marks a decoded column that can be NULL although its declared value type
185/// is not an `Option`: a column from the nullable side of an outer join, or a
186/// comparison whose operand can be NULL.
187///
188/// `MaybeNull<T>` only matches `Option<T>` in a decode target (and
189/// `MaybeNull<Option<T>>` matches `Option<T>`), never a bare `T`.
190#[doc(hidden)]
191#[derive(Debug, Clone, Copy, Default)]
192pub struct MaybeNull<T>(PhantomData<T>);
193
194/// Checks an explicit SELECT list against the query scope.
195///
196/// Each expression's sources must be in `Scope`. The resulting column list
197/// widens a column to [`MaybeNull`] when an outer join can make it NULL.
198#[doc(hidden)]
199pub trait ProjectionIn<Scope, Proof> {
200    /// Column types the decode target is checked against.
201    type Columns: crate::TypeSet;
202}
203
204impl<Scope> ProjectionIn<Scope, ()> for Nil {
205    type Columns = Self;
206}
207
208impl<Head, Tail, Scope, HeadProof, TailProof> ProjectionIn<Scope, (HeadProof, TailProof)>
209    for Cons<Head, Tail>
210where
211    Head: crate::expr::ExprSources + ExprValueType,
212    Head::Sources: SourcesIn<Scope, HeadProof>,
213    Tail: ProjectionIn<Scope, TailProof>,
214{
215    type Columns = Cons<
216        <<Head::Sources as SourcesIn<Scope, HeadProof>>::Nullable as crate::expr::Nullability>::Decoded<
217            Head::ValueType,
218        >,
219        Tail::Columns,
220    >;
221}
222
223/// Field types of a `FromRow` selector, grouped by the source each reads.
224///
225/// Generated by `#[derive(SQLiteFromRow)]`, `#[derive(PostgresFromRow)]` and
226/// `#[derive(MySQLFromRow)]`. [`MarkerScopeValidFor`] requires every listed
227/// source to be in scope, and `Option` on every field read from the nullable
228/// side of an outer join.
229pub trait SelectTableFields {
230    /// `Cons<TableFields<Source, Cons<Field, ...>>, ...>`.
231    type TableFields;
232}
233
234/// Field types (a `Cons` list) that a `FromRow` selector reads from `Source`.
235#[derive(Debug, Clone, Copy, Default)]
236pub struct TableFields<Source, Fields>(PhantomData<(Source, Fields)>);
237
238/// The field list `Self` can hold values from a source with nullability
239/// `Nullable`: any fields for [`NonNull`](crate::expr::NonNull), only
240/// `Option` fields for [`Null`](crate::expr::Null).
241#[doc(hidden)]
242#[diagnostic::on_unimplemented(
243    message = "a field read from the nullable side of an outer join must be an `Option`",
244    label = "LEFT/RIGHT/FULL JOIN can return NULL for every column of this table",
245    note = "change the field type to `Option<_>`, or use an inner join"
246)]
247pub trait FieldsAcceptNullability<Nullable> {}
248
249impl<Fields> FieldsAcceptNullability<crate::expr::NonNull> for Fields {}
250
251impl FieldsAcceptNullability<crate::expr::Null> for Nil {}
252
253impl<T, Tail> FieldsAcceptNullability<crate::expr::Null> for Cons<Option<T>, Tail> where
254    Tail: FieldsAcceptNullability<crate::expr::Null>
255{
256}
257
258/// Checks a [`SelectTableFields`] list against the query scope.
259#[doc(hidden)]
260pub trait TableFieldsIn<Scope, Proof> {}
261
262impl<Scope> TableFieldsIn<Scope, ()> for Nil {}
263
264impl<Source, Fields, Tail, Scope, Witness, TailProof> TableFieldsIn<Scope, (Witness, TailProof)>
265    for Cons<TableFields<Source, Fields>, Tail>
266where
267    Source: ScopeEntry,
268    Scope: ScopeContains<Source::Key, Witness>,
269    Fields: FieldsAcceptNullability<<Scope as ScopeContains<Source::Key, Witness>>::Nullable>,
270    Tail: TableFieldsIn<Scope, TailProof>,
271{
272}
273
274// =============================================================================
275// Aggregate status validation for SELECT lists
276// =============================================================================
277
278/// Combined aggregate status of a tuple of expressions.
279///
280/// A 1-tuple has its element's status. Longer tuples fold the statuses with
281/// [`CombineAggStatus`](crate::expr::CombineAggStatus).
282pub trait AggStatus {
283    /// The combined status.
284    type Status;
285}
286
287// 1-tuple base case
288impl<E: crate::expr::HasAggStatus> AggStatus for (E,) {
289    type Status = E::Status;
290}
291
292// Generate AggStatus for 2..N tuples.
293// The `with_col_sizes_*` macros call this incrementally as:
294//   callback!(T0; 0)  callback!(T0, T1; 0, 1)  callback!(T0, T1, T2; 0, 1, 2)  ...
295// We skip the 1-tuple (handled above) and implement 2+ tuples.
296macro_rules! impl_tuple_agg_status {
297    // 1-tuple: skip (already implemented above)
298    ($E0:ident; $i0:tt) => {};
299    // 2-tuple
300    ($E0:ident, $E1:ident; $i0:tt, $i1:tt) => {
301        impl<$E0, $E1> AggStatus for ($E0, $E1)
302        where
303            $E0: crate::expr::HasAggStatus,
304            $E1: crate::expr::HasAggStatus,
305            <$E0 as crate::expr::HasAggStatus>::Status:
306                crate::expr::CombineAggStatus<<$E1 as crate::expr::HasAggStatus>::Status>,
307        {
308            type Status = <<$E0 as crate::expr::HasAggStatus>::Status as
309                crate::expr::CombineAggStatus<<$E1 as crate::expr::HasAggStatus>::Status>>::Output;
310        }
311    };
312    // 3+ tuples: fold head element's status with the rest-tuple's status
313    ($E0:ident, $E1:ident, $($rest:ident),+; $i0:tt, $i1:tt, $($ri:tt),+) => {
314        impl<$E0, $E1, $($rest),+> AggStatus for ($E0, $E1, $($rest),+)
315        where
316            $E0: crate::expr::HasAggStatus,
317            ($E1, $($rest),+): AggStatus,
318            <$E0 as crate::expr::HasAggStatus>::Status:
319                crate::expr::CombineAggStatus<<($E1, $($rest),+) as AggStatus>::Status>,
320        {
321            type Status = <<$E0 as crate::expr::HasAggStatus>::Status as
322                crate::expr::CombineAggStatus<<($E1, $($rest),+) as AggStatus>::Status>>::Output;
323        }
324    };
325}
326
327with_col_sizes_8!(impl_tuple_agg_status);
328
329#[cfg(any(
330    feature = "col16",
331    feature = "col32",
332    feature = "col64",
333    feature = "col128",
334    feature = "col200"
335))]
336with_col_sizes_16!(impl_tuple_agg_status);
337
338#[cfg(any(
339    feature = "col32",
340    feature = "col64",
341    feature = "col128",
342    feature = "col200"
343))]
344with_col_sizes_32!(impl_tuple_agg_status);
345
346#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
347with_col_sizes_64!(impl_tuple_agg_status);
348
349#[cfg(any(feature = "col128", feature = "col200"))]
350with_col_sizes_128!(impl_tuple_agg_status);
351
352#[cfg(feature = "col200")]
353with_col_sizes_200!(impl_tuple_agg_status);
354
355// =============================================================================
356// GROUP BY column tracking
357// =============================================================================
358
359/// Something that can be passed to `.group_by()`: a column or a tuple of
360/// columns.
361///
362/// The table macros implement this for each column; tuples are implemented
363/// here. `Columns` lists the grouped columns so the SELECT list can be
364/// checked against them ([`MarkerAggValidFor`]).
365pub trait IntoGroupBy<'a, V: crate::SQLParam + 'a>:
366    crate::ToSQL<'a, V> + crate::expr::ExprSources
367{
368    /// Grouped columns as a type-level list (`Cons<Col1, Cons<Col2, Nil>>`),
369    /// or [`PkGroup<T>`] when grouping by a table's single primary key.
370    type Columns;
371}
372
373// Single column → Cons<Self, Nil>
374// (Implemented by proc macros for each column ZST)
375
376/// GROUP BY marker: the group key is `Table`'s single-column primary key.
377///
378/// The table macros produce this when `.group_by(col)` is called with a
379/// table's only primary-key column. Every other column of that table depends
380/// on its primary key (SQL:1999 functional dependency), so any column of
381/// `Table` may be selected without being listed in GROUP BY. Columns of
382/// other tables (for example joined ones) must still be aggregated.
383///
384/// Grouping by the bare primary key also lets the database read groups in
385/// key order instead of sorting the whole result, which helps
386/// `GROUP BY ... ORDER BY pk LIMIT n`.
387#[derive(Debug, Clone, Copy, Default)]
388pub struct PkGroup<Table>(PhantomData<Table>);
389
390// Tuple impls: (Col1, Col2) → Cons<Col1, Cons<Col2, Nil>>
391macro_rules! impl_into_group_by_tuple {
392    // 1-tuple: skip (single column uses direct impl)
393    ($T0:ident; $i0:tt) => {};
394    // 2-tuple
395    ($T0:ident, $T1:ident; $i0:tt, $i1:tt) => {
396        impl<'a, V: crate::SQLParam + 'a, $T0, $T1> IntoGroupBy<'a, V> for ($T0, $T1)
397        where
398            $T0: crate::ToSQL<'a, V> + crate::expr::ExprSources,
399            $T1: crate::ToSQL<'a, V> + crate::expr::ExprSources,
400        {
401            type Columns = Cons<$T0, Cons<$T1, Nil>>;
402        }
403    };
404    // 3+ tuples
405    ($T0:ident, $T1:ident, $($rest:ident),+; $i0:tt, $i1:tt, $($ri:tt),+) => {
406        impl<'a, V: crate::SQLParam + 'a, $T0, $T1, $($rest),+> IntoGroupBy<'a, V> for ($T0, $T1, $($rest),+)
407        where
408            $T0: crate::ToSQL<'a, V> + crate::expr::ExprSources,
409            $T1: crate::ToSQL<'a, V> + crate::expr::ExprSources,
410            $($rest: crate::ToSQL<'a, V> + crate::expr::ExprSources,)+
411        {
412            type Columns = impl_into_group_by_tuple!(@cons $T0, $T1, $($rest),+);
413        }
414    };
415    // Helper: build nested Cons type
416    (@cons $T:ident) => { Cons<$T, Nil> };
417    (@cons $T:ident, $($rest:ident),+) => { Cons<$T, impl_into_group_by_tuple!(@cons $($rest),+)> };
418}
419
420with_col_sizes_8!(impl_into_group_by_tuple);
421
422#[cfg(any(
423    feature = "col16",
424    feature = "col32",
425    feature = "col64",
426    feature = "col128",
427    feature = "col200"
428))]
429with_col_sizes_16!(impl_into_group_by_tuple);
430
431// =============================================================================
432// Scalar column validation against grouped columns
433// =============================================================================
434
435/// Every non-aggregate column in a selected tuple is in the `Grouped` list.
436/// Aggregate columns are skipped.
437///
438/// `Proof` is a witness type the compiler infers (like
439/// [`ListContains`](crate::scope::ListContains)).
440#[diagnostic::on_unimplemented(
441    message = "non-aggregate column in SELECT is not in GROUP BY",
442    label = "this column must appear in .group_by(...) or be wrapped in an aggregate function",
443    note = "when using GROUP BY, every non-aggregate column in SELECT must be listed in GROUP BY, \
444            unless the group key is the column's table primary key (`.group_by(table.pk)`)"
445)]
446pub trait ScalarColumnsIn<Grouped, Proof> {}
447
448/// GROUP BY proof: the column is an aggregate, so it need not be grouped.
449pub struct AggSkip;
450
451/// GROUP BY proof: the scalar column is in the grouped list at the position
452/// `W` proves.
453pub struct ScalarCheck<W>(core::marker::PhantomData<W>);
454
455/// GROUP BY proof: the scalar column is allowed because the group key is its
456/// table's primary key (functional dependency).
457pub struct PkDependent;
458
459// 1-tuple
460impl<E, Grouped, Proof> ScalarColumnsIn<Grouped, (Proof,)> for (E,) where
461    E: SingleColGroupCheck<Grouped, Proof>
462{
463}
464
465/// GROUP BY check for one selected column: aggregates pass, scalars must be
466/// grouped.
467#[diagnostic::on_unimplemented(
468    message = "`{Self}` is selected next to an aggregate but is not grouped",
469    label = "this query mixes aggregated and ungrouped columns",
470    note = "add the column to `.group_by(...)`, or wrap it in an aggregate such as `max(...)`"
471)]
472pub trait SingleColGroupCheck<Grouped, Proof> {}
473
474/// The column an expression is matched as when checking GROUP BY.
475///
476/// An aliased column (`AliasedExpr<Col>`) matches as `Col`; a bare column or
477/// any other expression matches as itself.
478pub trait GroupByIdentity {
479    /// The type looked up in the grouped column list.
480    type Identity;
481}
482
483// Default: identity is self (bare column ZSTs)
484// (implemented by proc macros for each column ZST)
485
486// AliasedExpr unwraps to inner
487impl<E: GroupByIdentity> GroupByIdentity for crate::expr::AliasedExpr<E> {
488    type Identity = E::Identity;
489}
490
491// SQLExpr: identity is self (for aggregate expressions, this won't be checked anyway)
492impl<V: crate::SQLParam, T, N, A, S> GroupByIdentity for crate::expr::SQLExpr<'_, V, T, N, A, S>
493where
494    T: crate::types::DataType,
495    N: crate::expr::Nullability,
496    A: crate::expr::AggregateKind,
497{
498    type Identity = Self;
499}
500
501// ColumnBinOp: identity is self (complex expressions won't match GROUP BY)
502impl<Lhs, Rhs, Op, D, SQLType, Nullable> GroupByIdentity
503    for crate::expr::ColumnBinOp<Lhs, Rhs, Op, D, SQLType, Nullable>
504{
505    type Identity = Self;
506}
507
508// ColumnNeg: identity is self
509impl<T, D, SQLType, Nullable> GroupByIdentity for crate::expr::ColumnNeg<T, D, SQLType, Nullable> {
510    type Identity = Self;
511}
512
513// Aggregate expressions → always OK
514impl<E, Grouped> SingleColGroupCheck<Grouped, AggSkip> for E where
515    E: crate::expr::HasAggStatus<Status = crate::expr::AllAgg>
516{
517}
518
519// Scalar expressions → base column identity must be in Grouped list
520impl<E, Grouped, W> SingleColGroupCheck<Grouped, ScalarCheck<W>> for E
521where
522    E: crate::expr::HasAggStatus<Status = crate::expr::AllScalar> + GroupByIdentity,
523    Grouped: crate::scope::ListContains<E::Identity, W>,
524{
525}
526
527// Scalar expressions under a primary-key group → the whole row of that table
528// is functionally dependent on the group key, so any column of the grouped
529// table passes. No overlap with the `ScalarCheck` impl above: `PkGroup<T>`
530// never implements `ListContains`.
531impl<E, T> SingleColGroupCheck<PkGroup<T>, PkDependent> for E
532where
533    E: crate::expr::HasAggStatus<Status = crate::expr::AllScalar> + GroupByIdentity,
534    E::Identity: crate::traits::ColumnOf<T>,
535{
536}
537
538// N-tuple: check head element, recurse on tail
539// Uses (HeadProof, TailProof) witness structure, like ListIncludes.
540
541// 2-tuple
542impl<T0, T1, Grouped, P0, P1> ScalarColumnsIn<Grouped, (P0, P1)> for (T0, T1)
543where
544    T0: SingleColGroupCheck<Grouped, P0>,
545    T1: SingleColGroupCheck<Grouped, P1>,
546{
547}
548
549// 3+ tuples: check head, recurse on (T1, T2, ...)
550macro_rules! impl_scalar_columns_in {
551    // 1-tuple: skip (handled above directly)
552    ($T0:ident; $i0:tt) => {};
553    // 2-tuple: skip (handled above directly)
554    ($T0:ident, $T1:ident; $i0:tt, $i1:tt) => {};
555    // 3+ tuples: head + tail recursion
556    ($T0:ident, $($rest:ident),+; $i0:tt, $($ri:tt),+) => {
557        impl<$T0, $($rest),+, Grouped, HeadProof, TailProof>
558            ScalarColumnsIn<Grouped, (HeadProof, TailProof)>
559            for ($T0, $($rest),+)
560        where
561            $T0: SingleColGroupCheck<Grouped, HeadProof>,
562            ($($rest,)+): ScalarColumnsIn<Grouped, TailProof>,
563        {}
564    };
565}
566
567with_col_sizes_8!(impl_scalar_columns_in);
568
569#[cfg(any(
570    feature = "col16",
571    feature = "col32",
572    feature = "col64",
573    feature = "col128",
574    feature = "col200"
575))]
576with_col_sizes_16!(impl_scalar_columns_in);
577
578// =============================================================================
579// MarkerAggValidFor — top-level bound on terminal methods
580// =============================================================================
581
582/// The SELECT list is valid for the query's GROUP BY.
583///
584/// `.all()`, `.get()` and `.rows()` require this bound.
585///
586/// - `Grouped = ()` (no GROUP BY): any mix of columns is accepted.
587/// - `Grouped = Cons<...>`: each non-aggregate column of an explicit SELECT
588///   list must be in the list.
589/// - `Grouped = PkGroup<T>`: each non-aggregate column must belong to `T`.
590///
591/// `SELECT *`, raw SQL and `FromRow` selections are not checked.
592#[diagnostic::on_unimplemented(
593    message = "non-aggregate column in SELECT is not in GROUP BY",
594    label = "add this column to .group_by(...) or wrap it in an aggregate function"
595)]
596pub trait MarkerAggValidFor<Grouped, Proof = ()> {}
597
598// No GROUP BY (Grouped = ()) → always valid, any mix is fine
599impl<Mk> MarkerAggValidFor<()> for Mk {}
600
601// SelectStar with GROUP BY: can't check at compile time, always passes
602impl<Scope, Used, Head, Tail> MarkerAggValidFor<Cons<Head, Tail>>
603    for Scoped<SelectStar, Scope, Used>
604{
605}
606
607// SelectExpr with GROUP BY: can't check, always passes
608impl<Scope, Used, Head, Tail> MarkerAggValidFor<Cons<Head, Tail>>
609    for Scoped<SelectExpr, Scope, Used>
610{
611}
612
613// SelectAs with GROUP BY: user-specified type, always passes
614impl<Scope, Used, R, Head, Tail> MarkerAggValidFor<Cons<Head, Tail>>
615    for Scoped<SelectAs<R>, Scope, Used>
616{
617}
618
619// SelectCols with GROUP BY: check each scalar column is in the Grouped list
620impl<Scope, Used, Cols, Head, Tail, Proof> MarkerAggValidFor<Cons<Head, Tail>, Proof>
621    for Scoped<SelectCols<Cols>, Scope, Used>
622where
623    Cols: ScalarColumnsIn<Cons<Head, Tail>, Proof>,
624{
625}
626
627// GROUP BY a table's primary key (`Grouped = PkGroup<T>`): same shape as the
628// Cons impls above, but scalar columns are checked for membership in the
629// grouped table instead of the grouped column list.
630impl<Scope, Used, T> MarkerAggValidFor<PkGroup<T>> for Scoped<SelectStar, Scope, Used> {}
631
632impl<Scope, Used, T> MarkerAggValidFor<PkGroup<T>> for Scoped<SelectExpr, Scope, Used> {}
633
634impl<Scope, Used, R, T> MarkerAggValidFor<PkGroup<T>> for Scoped<SelectAs<R>, Scope, Used> {}
635
636impl<Scope, Used, Cols, T, Proof> MarkerAggValidFor<PkGroup<T>, Proof>
637    for Scoped<SelectCols<Cols>, Scope, Used>
638where
639    Cols: ScalarColumnsIn<PkGroup<T>, Proof>,
640{
641}
642
643// =============================================================================
644// Marker column-count validation for strict decode paths
645// =============================================================================
646
647/// The columns a decode target reads, as a type-level list.
648///
649/// Each column is one `Cons<T, ...>` node, where `T` is the Rust type it
650/// decodes into. Tuples concatenate their elements' lists.
651pub trait RowColumnList<Row: ?Sized> {
652    /// `Cons<T0, Cons<T1, ... Nil>>`.
653    type Columns: crate::TypeSet;
654}
655
656/// The value types of a selected column tuple, as a type-level list.
657pub trait SelectedColumnList {
658    /// `Cons<T0, Cons<T1, ... Nil>>`.
659    type Columns: crate::TypeSet;
660}
661
662/// Type-level expression list for an explicit SELECT projection.
663///
664/// Unlike [`SelectedColumnList`], this preserves each expression type so a
665/// dialect can validate SQL types and nullability at a later boundary such as
666/// `INSERT ... SELECT`.
667#[doc(hidden)]
668pub trait SelectedExpressionList {
669    type Expressions: crate::TypeSet;
670}
671
672trait SameType<T> {}
673impl<T> SameType<T> for T {}
674
675#[diagnostic::on_unimplemented(
676    message = "selected column decodes as `{Expected}`, but the decode target uses `{Actual}`",
677    label = "the decode target does not match the selected columns",
678    note = "a selected `MaybeNull<T>` can be NULL (an outer join or a nullable operand) \
679            and must be decoded as `Option<T>`"
680)]
681trait ColumnTypeCompatible<Row: ?Sized, Expected, Actual> {}
682
683impl<Row: ?Sized, T> ColumnTypeCompatible<Row, T, T> for () {}
684
685// A column from the nullable side of an outer join decodes only into `Option`.
686// The accepted inner types live on a separate trait so a decode error lists
687// one candidate here instead of every widened variant.
688impl<Row: ?Sized, Expected, Actual> ColumnTypeCompatible<Row, MaybeNull<Expected>, Option<Actual>>
689    for ()
690where
691    (): MaybeNullCompatible<Row, Expected, Actual>,
692{
693}
694
695/// Inner-type rule for [`MaybeNull`] columns: `Expected` is the column's
696/// own decoded type, `Actual` the type inside the target's `Option`.
697trait MaybeNullCompatible<Row: ?Sized, Expected, Actual> {}
698
699impl<Row: ?Sized, T> MaybeNullCompatible<Row, T, T> for () {}
700
701impl<Row: ?Sized, T> MaybeNullCompatible<Row, Option<T>, T> for () {}
702
703trait TypeListCompatible<Row: ?Sized, ActualList> {}
704
705impl<Row: ?Sized> TypeListCompatible<Row, Self> for crate::Nil {}
706
707impl<Row: ?Sized, EH, ET, AH, AT> TypeListCompatible<Row, crate::Cons<AH, AT>>
708    for crate::Cons<EH, ET>
709where
710    (): ColumnTypeCompatible<Row, EH, AH>,
711    ET: TypeListCompatible<Row, AT>,
712{
713}
714
715trait SqliteDecodeRow {}
716
717#[cfg(feature = "rusqlite")]
718impl SqliteDecodeRow for ::rusqlite::Row<'_> {}
719
720#[cfg(feature = "libsql")]
721impl SqliteDecodeRow for ::libsql::Row {}
722
723#[cfg(feature = "turso")]
724impl SqliteDecodeRow for ::turso::Row {}
725
726macro_rules! impl_sqlite_integer_decode_compat {
727    ($expected:ty => $($actual:ty),+ $(,)?) => {
728        $(
729            impl<Row> ColumnTypeCompatible<Row, $expected, $actual> for ()
730            where
731                Row: SqliteDecodeRow,
732            {
733            }
734        )+
735    };
736}
737
738impl_sqlite_integer_decode_compat!(
739    i64 => i8, i16, i32, isize, u8, u16, u32, u64, usize, bool
740);
741
742macro_rules! impl_sqlite_join_nullable_integer_decode_compat {
743    ($($actual:ty),+ $(,)?) => {
744        $(
745            impl<Row> MaybeNullCompatible<Row, i64, $actual> for ()
746            where
747                Row: SqliteDecodeRow,
748            {
749            }
750
751            impl<Row> MaybeNullCompatible<Row, Option<i64>, $actual> for ()
752            where
753                Row: SqliteDecodeRow,
754            {
755            }
756        )+
757    };
758}
759
760impl_sqlite_join_nullable_integer_decode_compat!(
761    i8, i16, i32, isize, u8, u16, u32, u64, usize, bool
762);
763
764impl_sqlite_integer_decode_compat!(
765    Option<i64> =>
766        Option<i8>,
767        Option<i16>,
768        Option<i32>,
769        Option<isize>,
770        Option<u8>,
771        Option<u16>,
772        Option<u32>,
773        Option<u64>,
774        Option<usize>,
775        Option<bool>
776);
777
778macro_rules! impl_row_column_list_one {
779    ($($ty:ty),+ $(,)?) => {
780        $(
781            impl<Row: ?Sized> RowColumnList<Row> for $ty {
782                type Columns = crate::Cons<$ty, crate::Nil>;
783            }
784        )+
785    };
786}
787
788impl_row_column_list_one!(
789    i8,
790    i16,
791    i32,
792    i64,
793    isize,
794    u8,
795    u16,
796    u32,
797    u64,
798    usize,
799    f32,
800    f64,
801    bool,
802    crate::prelude::String,
803    crate::prelude::Vec<u8>
804);
805
806impl<Row: ?Sized> RowColumnList<Row> for () {
807    type Columns = crate::Cons<(), crate::Nil>;
808}
809
810#[cfg(feature = "uuid")]
811impl<Row: ?Sized> RowColumnList<Row> for uuid::Uuid {
812    type Columns = crate::Cons<Self, crate::Nil>;
813}
814
815#[cfg(feature = "chrono")]
816impl<Row: ?Sized> RowColumnList<Row> for chrono::NaiveDate {
817    type Columns = crate::Cons<Self, crate::Nil>;
818}
819
820#[cfg(feature = "chrono")]
821impl<Row: ?Sized> RowColumnList<Row> for chrono::NaiveTime {
822    type Columns = crate::Cons<Self, crate::Nil>;
823}
824
825#[cfg(feature = "chrono")]
826impl<Row: ?Sized> RowColumnList<Row> for chrono::NaiveDateTime {
827    type Columns = crate::Cons<Self, crate::Nil>;
828}
829
830#[cfg(feature = "chrono")]
831impl<Row: ?Sized> RowColumnList<Row> for chrono::DateTime<chrono::Utc> {
832    type Columns = crate::Cons<Self, crate::Nil>;
833}
834
835#[cfg(feature = "serde")]
836impl<Row: ?Sized> RowColumnList<Row> for serde_json::Value {
837    type Columns = crate::Cons<Self, crate::Nil>;
838}
839
840#[cfg(feature = "rust-decimal")]
841impl<Row: ?Sized> RowColumnList<Row> for rust_decimal::Decimal {
842    type Columns = crate::Cons<Self, crate::Nil>;
843}
844
845#[cfg(feature = "chrono")]
846impl<Row: ?Sized> RowColumnList<Row> for chrono::Duration {
847    type Columns = crate::Cons<Self, crate::Nil>;
848}
849
850#[cfg(feature = "time")]
851impl<Row: ?Sized> RowColumnList<Row> for time::Date {
852    type Columns = crate::Cons<Self, crate::Nil>;
853}
854
855#[cfg(feature = "time")]
856impl<Row: ?Sized> RowColumnList<Row> for time::Time {
857    type Columns = crate::Cons<Self, crate::Nil>;
858}
859
860#[cfg(feature = "time")]
861impl<Row: ?Sized> RowColumnList<Row> for time::PrimitiveDateTime {
862    type Columns = crate::Cons<Self, crate::Nil>;
863}
864
865#[cfg(feature = "time")]
866impl<Row: ?Sized> RowColumnList<Row> for time::OffsetDateTime {
867    type Columns = crate::Cons<Self, crate::Nil>;
868}
869
870#[cfg(feature = "time")]
871impl<Row: ?Sized> RowColumnList<Row> for time::Duration {
872    type Columns = crate::Cons<Self, crate::Nil>;
873}
874
875#[cfg(feature = "jiff")]
876impl<Row: ?Sized> RowColumnList<Row> for jiff::civil::Date {
877    type Columns = crate::Cons<Self, crate::Nil>;
878}
879
880#[cfg(feature = "jiff")]
881impl<Row: ?Sized> RowColumnList<Row> for jiff::civil::Time {
882    type Columns = crate::Cons<Self, crate::Nil>;
883}
884
885#[cfg(feature = "jiff")]
886impl<Row: ?Sized> RowColumnList<Row> for jiff::civil::DateTime {
887    type Columns = crate::Cons<Self, crate::Nil>;
888}
889
890#[cfg(feature = "jiff")]
891impl<Row: ?Sized> RowColumnList<Row> for jiff::Timestamp {
892    type Columns = crate::Cons<Self, crate::Nil>;
893}
894
895#[cfg(feature = "cidr")]
896impl<Row: ?Sized> RowColumnList<Row> for cidr::IpInet {
897    type Columns = crate::Cons<Self, crate::Nil>;
898}
899
900#[cfg(feature = "cidr")]
901impl<Row: ?Sized> RowColumnList<Row> for cidr::IpCidr {
902    type Columns = crate::Cons<Self, crate::Nil>;
903}
904
905#[cfg(feature = "geo-types")]
906impl<Row: ?Sized> RowColumnList<Row> for geo_types::Point<f64> {
907    type Columns = crate::Cons<Self, crate::Nil>;
908}
909
910#[cfg(feature = "geo-types")]
911impl<Row: ?Sized> RowColumnList<Row> for geo_types::LineString<f64> {
912    type Columns = crate::Cons<Self, crate::Nil>;
913}
914
915#[cfg(feature = "geo-types")]
916impl<Row: ?Sized> RowColumnList<Row> for geo_types::Rect<f64> {
917    type Columns = crate::Cons<Self, crate::Nil>;
918}
919
920#[cfg(feature = "bit-vec")]
921impl<Row: ?Sized> RowColumnList<Row> for bit_vec::BitVec {
922    type Columns = crate::Cons<Self, crate::Nil>;
923}
924
925#[cfg(feature = "arrayvec")]
926impl<Row: ?Sized, const N: usize> RowColumnList<Row> for arrayvec::ArrayString<N> {
927    type Columns = crate::Cons<Self, crate::Nil>;
928}
929
930#[cfg(feature = "arrayvec")]
931impl<Row: ?Sized, T, const N: usize> RowColumnList<Row> for arrayvec::ArrayVec<T, N> {
932    type Columns = crate::Cons<Self, crate::Nil>;
933}
934
935impl<Row: ?Sized> RowColumnList<Row> for compact_str::CompactString {
936    type Columns = crate::Cons<Self, crate::Nil>;
937}
938
939#[cfg(feature = "bytes")]
940impl<Row: ?Sized> RowColumnList<Row> for bytes::Bytes {
941    type Columns = crate::Cons<Self, crate::Nil>;
942}
943
944#[cfg(feature = "bytes")]
945impl<Row: ?Sized> RowColumnList<Row> for bytes::BytesMut {
946    type Columns = crate::Cons<Self, crate::Nil>;
947}
948
949impl<Row: ?Sized, A: smallvec::Array> RowColumnList<Row> for smallvec::SmallVec<A> {
950    type Columns = crate::Cons<Self, crate::Nil>;
951}
952
953impl<Row: ?Sized, T> RowColumnList<Row> for Option<T> {
954    type Columns = crate::Cons<Self, crate::Nil>;
955}
956
957/// Helper: split last element from a type list and generate `RowColumnList` impl.
958/// Called by `impl_rcl_tuple` after separating first from rest.
959macro_rules! impl_rcl_body {
960    // 1-tuple: just delegate
961    ([$A:ident] []) => {
962        impl<Row: ?Sized, $A: RowColumnList<Row>> RowColumnList<Row> for ($A,) {
963            type Columns = <$A as RowColumnList<Row>>::Columns;
964        }
965    };
966    // N-tuple: delegate to (N-1)-tuple, concat last
967    ([$($all:ident),+] [$($prev:ident),+; $last:ident]) => {
968        impl<Row: ?Sized, $($all),+> RowColumnList<Row> for ($($all,)+)
969        where
970            $last: RowColumnList<Row>,
971            ($($prev,)+): RowColumnList<Row>,
972            <($($prev,)+) as RowColumnList<Row>>::Columns:
973                crate::Concat<<$last as RowColumnList<Row>>::Columns>,
974        {
975            type Columns = <<($($prev,)+) as RowColumnList<Row>>::Columns as crate::Concat<
976                <$last as RowColumnList<Row>>::Columns,
977            >>::Output;
978        }
979    };
980}
981
982/// Callback for `with_type_sizes_*!`: receives all types, separates last via
983/// recursive accumulator, then delegates to `impl_rcl_body`.
984macro_rules! impl_rcl_tuple {
985    ($($T:ident),+) => {
986        impl_rcl_split!([$($T),+] [] $($T),+);
987    };
988}
989
990/// Recursive accumulator to split `[all] [prev...] remaining...`
991macro_rules! impl_rcl_split {
992    // 1-tuple: no prev, single element
993    ([$A:ident] [] $only:ident) => {
994        impl_rcl_body!([$A] []);
995    };
996    // Base: one element left in remaining = it's the last
997    ([$($all:ident),+] [$($prev:ident),+] $last:ident) => {
998        impl_rcl_body!([$($all),+] [$($prev),+; $last]);
999    };
1000    // Recurse from empty prev
1001    ([$($all:ident),+] [] $head:ident, $($rest:ident),+) => {
1002        impl_rcl_split!([$($all),+] [$head] $($rest),+);
1003    };
1004    // Recurse with non-empty prev
1005    ([$($all:ident),+] [$($prev:ident),+] $head:ident, $($rest:ident),+) => {
1006        impl_rcl_split!([$($all),+] [$($prev),+, $head] $($rest),+);
1007    };
1008}
1009
1010with_type_sizes_8!(impl_rcl_tuple);
1011
1012#[cfg(any(
1013    feature = "col16",
1014    feature = "col32",
1015    feature = "col64",
1016    feature = "col128",
1017    feature = "col200"
1018))]
1019with_type_sizes_16!(impl_rcl_tuple);
1020
1021#[cfg(any(
1022    feature = "col32",
1023    feature = "col64",
1024    feature = "col128",
1025    feature = "col200"
1026))]
1027with_type_sizes_32!(impl_rcl_tuple);
1028
1029/// The decode target `Actual` matches what the query selects.
1030///
1031/// `.all()`, `.get()` and `.rows()` require this bound. `Inferred` is the
1032/// query's inferred row type and `Actual` the type the caller decodes into.
1033///
1034/// - Explicit columns: each column of `Actual` must have the selected
1035///   column's type, and must be `Option` when an outer join or a nullable
1036///   operand can make it NULL.
1037/// - Joined `SELECT *`: `Actual` must keep the inferred shape (see
1038///   [`JoinedStarRow`]).
1039/// - Raw SQL: `Actual` must equal `Inferred`.
1040/// - Single-table `SELECT *` and `FromRow` selections are not checked here.
1041///
1042/// `Proof` is the same witness the terminal method infers for
1043/// [`MarkerScopeValidFor`], so outer-join nullability found while checking
1044/// scope also decides which decoded columns must be `Option`.
1045#[diagnostic::on_unimplemented(
1046    message = "selected shape does not match decode target `{Actual}`",
1047    label = "this decode target is not type-compatible with .select(...) output",
1048    note = "use typed expressions or derive FromRow for explicit remapping when selecting custom expressions"
1049)]
1050pub trait MarkerColumnCountValid<Row: ?Sized, Inferred, Actual, Proof = ()> {}
1051
1052/// The select marker can be decoded by `.all()` / `.get()` without an
1053/// explicit row type.
1054///
1055/// A raw `select(sql!(...))` is excluded on purpose: give it a type with a
1056/// typed expression (`raw_non_null`, `raw_nullable`) or select into a
1057/// `FromRow` struct instead.
1058#[diagnostic::on_unimplemented(
1059    message = "raw select expressions require explicit typing in strict decode",
1060    label = "`select(sql!(...)).all()/get()` is not allowed in strict mode",
1061    note = "use typed wrappers like `raw_non_null`/`raw_nullable` or derive FromRow"
1062)]
1063pub trait StrictDecodeMarker {}
1064
1065impl StrictDecodeMarker for SelectStar {}
1066impl<Cols> StrictDecodeMarker for SelectCols<Cols> {}
1067impl<R> StrictDecodeMarker for SelectAs<R> {}
1068impl<M, Scope, Used> StrictDecodeMarker for Scoped<M, Scope, Used> where M: StrictDecodeMarker {}
1069
1070impl<Row: ?Sized, Inferred, Actual, Proof> MarkerColumnCountValid<Row, Inferred, Actual, Proof>
1071    for SelectStar
1072{
1073}
1074
1075impl<Row: ?Sized, Cols, Inferred, Actual, Proof>
1076    MarkerColumnCountValid<Row, Inferred, Actual, Proof> for SelectCols<Cols>
1077where
1078    Cols: SelectedColumnList,
1079    Actual: RowColumnList<Row>,
1080    <Cols as SelectedColumnList>::Columns:
1081        TypeListCompatible<Row, <Actual as RowColumnList<Row>>::Columns>,
1082{
1083}
1084
1085impl<Row: ?Sized, Inferred, Actual, Proof> MarkerColumnCountValid<Row, Inferred, Actual, Proof>
1086    for SelectExpr
1087where
1088    Inferred: SameType<Actual>,
1089{
1090}
1091
1092impl<Row: ?Sized, R, Inferred, Actual, Proof> MarkerColumnCountValid<Row, Inferred, Actual, Proof>
1093    for SelectAs<R>
1094{
1095}
1096
1097/// Single-source `SELECT *`: the table model may be decoded into any row type.
1098impl<Row: ?Sized, Table, Used, Inferred, Actual, Proof>
1099    MarkerColumnCountValid<Row, Inferred, Actual, Proof>
1100    for Scoped<SelectStar, Cons<Table, Nil>, Used>
1101{
1102}
1103
1104/// Joined `SELECT *`: the decode target must keep the inferred row shape, with
1105/// `Option` on every source that an outer join can leave NULL.
1106impl<Row: ?Sized, First, Second, Rest, Used, Inferred, Actual, Proof>
1107    MarkerColumnCountValid<Row, Inferred, Actual, Proof>
1108    for Scoped<SelectStar, Cons<First, Cons<Second, Rest>>, Used>
1109where
1110    Inferred: JoinedStarRow<Actual>,
1111{
1112}
1113
1114impl<Row: ?Sized, Cols, Scope, Used, Inferred, Actual, UsedProof, ColsProof>
1115    MarkerColumnCountValid<Row, Inferred, Actual, (UsedProof, ColsProof)>
1116    for Scoped<SelectCols<Cols>, Scope, Used>
1117where
1118    Cols: SelectedExpressionList,
1119    Cols::Expressions: ProjectionIn<Scope, ColsProof>,
1120    Actual: RowColumnList<Row>,
1121    <Cols::Expressions as ProjectionIn<Scope, ColsProof>>::Columns:
1122        TypeListCompatible<Row, <Actual as RowColumnList<Row>>::Columns>,
1123{
1124}
1125
1126impl<Row: ?Sized, Scope, Used, Inferred, Actual, Proof>
1127    MarkerColumnCountValid<Row, Inferred, Actual, Proof> for Scoped<SelectExpr, Scope, Used>
1128where
1129    Inferred: SameType<Actual>,
1130{
1131}
1132
1133/// `FromRow` selectors are checked by [`MarkerScopeValidFor`].
1134impl<Row: ?Sized, R, Scope, Used, Inferred, Actual, Proof>
1135    MarkerColumnCountValid<Row, Inferred, Actual, Proof> for Scoped<SelectAs<R>, Scope, Used>
1136{
1137}
1138
1139/// Decode target for a joined `SELECT *` row.
1140///
1141/// Joins nest the inferred row as `(previous, joined)`. Each half must be
1142/// decoded as its inferred type; a half may additionally be widened to
1143/// `Option`, but a half the join already made `Option` cannot be narrowed.
1144#[diagnostic::on_unimplemented(
1145    message = "joined `SELECT *` rows decode as `{Self}`, not `{Actual}`",
1146    label = "the decode target does not match the joined row type",
1147    note = "LEFT/RIGHT/FULL JOIN sources can be NULL: decode them as `Option<_>`, \
1148            e.g. `(SelectUsers, Option<SelectPosts>)` after `.left_join(posts)`"
1149)]
1150pub trait JoinedStarRow<Actual> {}
1151
1152impl<A, B, ActualA, ActualB> JoinedStarRow<(ActualA, ActualB)> for (A, B)
1153where
1154    A: JoinedStarPart<ActualA>,
1155    B: JoinedStarPart<ActualB>,
1156{
1157}
1158
1159/// One half of a joined `SELECT *` row: exact, or widened to `Option`.
1160#[doc(hidden)]
1161#[diagnostic::on_unimplemented(
1162    message = "this half of the joined `SELECT *` row decodes as `{Self}`, not `{Actual}`",
1163    label = "the decode target does not match the joined row type",
1164    note = "LEFT/RIGHT/FULL JOIN sources can be NULL: decode them as `Option<_>`"
1165)]
1166pub trait JoinedStarPart<Actual> {}
1167
1168impl<T> JoinedStarPart<T> for T {}
1169
1170impl<T> JoinedStarPart<Option<T>> for T {}
1171
1172/// Decodes one result row into `R` the way the select marker `Self` asks.
1173///
1174/// `SelectAs<R>` uses `R: TryFrom<RowRef>` (the `FromRow` derive). Every
1175/// other marker uses [`FromDrizzleRow`].
1176pub trait DecodeSelectedRef<RowRef, R> {
1177    /// Decodes `row` into `R`.
1178    ///
1179    /// # Errors
1180    ///
1181    /// Returns an error if the row cannot be decoded into the expected type
1182    /// (missing columns, type mismatch, or downstream conversion failure).
1183    fn decode(row: RowRef) -> Result<R, DrizzleError>;
1184}
1185
1186impl<RowRef, R> DecodeSelectedRef<RowRef, R> for SelectAs<R>
1187where
1188    R: TryFrom<RowRef>,
1189    <R as TryFrom<RowRef>>::Error: Into<DrizzleError>,
1190{
1191    fn decode(row: RowRef) -> Result<R, DrizzleError> {
1192        R::try_from(row).map_err(Into::into)
1193    }
1194}
1195
1196impl<RowRef, R, M, Scope, Used> DecodeSelectedRef<RowRef, R> for Scoped<M, Scope, Used>
1197where
1198    M: DecodeSelectedRef<RowRef, R>,
1199{
1200    fn decode(row: RowRef) -> Result<R, DrizzleError> {
1201        M::decode(row)
1202    }
1203}
1204
1205impl<RowRef, Row: ?Sized, R> DecodeSelectedRef<RowRef, R> for SelectStar
1206where
1207    RowRef: core::ops::Deref<Target = Row>,
1208    R: FromDrizzleRow<Row>,
1209{
1210    fn decode(row: RowRef) -> Result<R, DrizzleError> {
1211        R::from_row(&*row)
1212    }
1213}
1214
1215impl<RowRef, Row: ?Sized, Cols, R> DecodeSelectedRef<RowRef, R> for SelectCols<Cols>
1216where
1217    RowRef: core::ops::Deref<Target = Row>,
1218    R: FromDrizzleRow<Row>,
1219{
1220    fn decode(row: RowRef) -> Result<R, DrizzleError> {
1221        R::from_row(&*row)
1222    }
1223}
1224
1225impl<RowRef, Row: ?Sized, R> DecodeSelectedRef<RowRef, R> for SelectExpr
1226where
1227    RowRef: core::ops::Deref<Target = Row>,
1228    R: FromDrizzleRow<Row>,
1229{
1230    fn decode(row: RowRef) -> Result<R, DrizzleError> {
1231        R::from_row(&*row)
1232    }
1233}
1234
1235// =============================================================================
1236// FromDrizzleRow — offset-based row extraction
1237// =============================================================================
1238
1239/// Reads a Rust value from a database row, starting at a column offset.
1240///
1241/// Unlike `TryFrom<Row>`, reading from an offset lets one joined row be split
1242/// across several model types. Tuples compose: `(A, B)` reads `A` at
1243/// `offset`, then `B` at `offset + A::COLUMN_COUNT`.
1244///
1245/// Implemented for scalar types per driver, for `Option<T>`, for tuples, and
1246/// by the `FromRow` derives and table macros for models.
1247#[diagnostic::on_unimplemented(
1248    message = "cannot deserialize `{Self}` from a database row",
1249    label = "this type does not implement FromDrizzleRow",
1250    note = "derive #[SQLiteFromRow], #[PostgresFromRow], or #[MySQLFromRow]"
1251)]
1252pub trait FromDrizzleRow<Row: ?Sized>: Sized {
1253    /// Number of columns this type reads from the row.
1254    const COLUMN_COUNT: usize;
1255
1256    /// Reads this type from `row`, starting at column `offset`.
1257    ///
1258    /// # Errors
1259    ///
1260    /// Returns an error if any column from `offset` through
1261    /// `offset + COLUMN_COUNT - 1` cannot be read or converted.
1262    fn from_row_at(row: &Row, offset: usize) -> Result<Self, DrizzleError>;
1263
1264    /// Reads this type from `row`, starting at column 0.
1265    ///
1266    /// # Errors
1267    ///
1268    /// Returns an error if the row cannot be decoded — see [`Self::from_row_at`].
1269    fn from_row(row: &Row) -> Result<Self, DrizzleError> {
1270        Self::from_row_at(row, 0)
1271    }
1272}
1273
1274/// A multi-column row type that can check whether it is absent (NULL).
1275///
1276/// This makes `Option<T>` work as a [`FromDrizzleRow`] target for a model,
1277/// as in a LEFT JOIN where the joined table may have no matching row.
1278///
1279/// The table macros implement this for each select model. Single-column
1280/// types (`i32`, `String`, ...) have their own `Option<T>` impls instead.
1281pub trait NullProbeRow<Row: ?Sized>: FromDrizzleRow<Row> {
1282    /// Returns `true` if the column at `offset` is NULL.
1283    ///
1284    /// # Errors
1285    ///
1286    /// Returns an error if the row cannot be inspected at `offset` (e.g. the
1287    /// driver reports an out-of-range index or conversion failure).
1288    fn is_null_at(row: &Row, offset: usize) -> Result<bool, DrizzleError>;
1289}
1290
1291// -- Tuple impls: generic over Row, composing inner impls --
1292
1293macro_rules! impl_from_drizzle_row_tuple {
1294    ($($T:ident),+; $($idx:tt),+) => {
1295        impl<__Row: ?Sized, $($T: FromDrizzleRow<__Row>),+> FromDrizzleRow<__Row> for ($($T,)+) {
1296            const COLUMN_COUNT: usize = 0 $(+ <$T as FromDrizzleRow<__Row>>::COLUMN_COUNT)+;
1297
1298            #[allow(non_snake_case)]
1299            fn from_row_at(
1300                row: &__Row,
1301                offset: usize,
1302            ) -> Result<Self, DrizzleError> {
1303                let mut __off = offset;
1304                $(
1305                    let $T = <$T as FromDrizzleRow<__Row>>::from_row_at(row, __off)?;
1306                    __off += <$T as FromDrizzleRow<__Row>>::COLUMN_COUNT;
1307                )+
1308                Ok(($($T,)+))
1309            }
1310        }
1311    };
1312}
1313
1314with_col_sizes_8!(impl_from_drizzle_row_tuple);
1315
1316#[cfg(any(
1317    feature = "col16",
1318    feature = "col32",
1319    feature = "col64",
1320    feature = "col128",
1321    feature = "col200"
1322))]
1323with_col_sizes_16!(impl_from_drizzle_row_tuple);
1324
1325#[cfg(any(
1326    feature = "col32",
1327    feature = "col64",
1328    feature = "col128",
1329    feature = "col200"
1330))]
1331with_col_sizes_32!(impl_from_drizzle_row_tuple);
1332
1333#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1334with_col_sizes_64!(impl_from_drizzle_row_tuple);
1335
1336#[cfg(any(feature = "col128", feature = "col200"))]
1337with_col_sizes_128!(impl_from_drizzle_row_tuple);
1338
1339#[cfg(feature = "col200")]
1340with_col_sizes_200!(impl_from_drizzle_row_tuple);
1341
1342// =============================================================================
1343// SQLTypeToRust — SQL type marker × dialect → canonical Rust type
1344// =============================================================================
1345
1346/// The default Rust type for a SQL type marker in dialect `D`.
1347///
1348/// `D` is a dialect marker ([`SQLiteDialect`], [`PostgresDialect`] or
1349/// [`MySQLDialect`]), so the mapping can differ per database. For example,
1350/// `postgres::types::Int4` maps to `i32` and `sqlite::types::Integer` to
1351/// `i64`. The selected column types of `.select(...)` come from here.
1352///
1353/// Some types map to a feature-gated Rust type (`chrono`, `time`, `jiff`,
1354/// `uuid`, `serde`, `cidr`, ...). Without any matching feature, some fall
1355/// back to `String`, while PostgreSQL date/time, `Uuid` and `Json`/`Jsonb`
1356/// have no mapping at all, which is a compile error naming the feature to
1357/// enable.
1358#[diagnostic::on_unimplemented(
1359    message = "SQL type `{Self}` has no default Rust mapping for dialect `{D}`",
1360    label = "this SQL type has no default Rust mapping for this dialect",
1361    note = "enable `chrono` for Date/Time/Timestamp/TimestampTz, `uuid` for Uuid, or `serde` for Json/Jsonb"
1362)]
1363pub trait SQLTypeToRust<D> {
1364    type RustType;
1365}
1366
1367// -- Dialect-native mappings ---------------------------------------------------
1368
1369use crate::dialect::{MySQLDialect, PostgresDialect, SQLiteDialect};
1370
1371impl<D, T> SQLTypeToRust<D> for crate::types::Array<T>
1372where
1373    T: crate::types::DataType + SQLTypeToRust<D>,
1374{
1375    type RustType = crate::prelude::Vec<<T as SQLTypeToRust<D>>::RustType>;
1376}
1377
1378impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Integer {
1379    type RustType = i64;
1380}
1381
1382impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Text {
1383    type RustType = crate::prelude::String;
1384}
1385
1386impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Real {
1387    type RustType = f64;
1388}
1389
1390impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Blob {
1391    type RustType = crate::prelude::Vec<u8>;
1392}
1393
1394impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Numeric {
1395    type RustType = f64;
1396}
1397
1398impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Any {
1399    type RustType = crate::prelude::String;
1400}
1401
1402macro_rules! impl_mysql_sql_type_to_rust {
1403    ($rust:ty => $($sql:ty),+ $(,)?) => {
1404        $(
1405            impl SQLTypeToRust<MySQLDialect> for $sql {
1406                type RustType = $rust;
1407            }
1408        )+
1409    };
1410}
1411
1412impl_mysql_sql_type_to_rust!(i8 => drizzle_types::mysql::types::TinyInt);
1413impl_mysql_sql_type_to_rust!(u8 => drizzle_types::mysql::types::TinyIntUnsigned);
1414impl_mysql_sql_type_to_rust!(i16 => drizzle_types::mysql::types::SmallInt);
1415impl_mysql_sql_type_to_rust!(u16 => drizzle_types::mysql::types::SmallIntUnsigned);
1416impl_mysql_sql_type_to_rust!(i32 =>
1417    drizzle_types::mysql::types::MediumInt,
1418    drizzle_types::mysql::types::Int,
1419);
1420impl_mysql_sql_type_to_rust!(u32 =>
1421    drizzle_types::mysql::types::MediumIntUnsigned,
1422    drizzle_types::mysql::types::IntUnsigned,
1423);
1424impl_mysql_sql_type_to_rust!(i64 => drizzle_types::mysql::types::BigInt);
1425impl_mysql_sql_type_to_rust!(u64 => drizzle_types::mysql::types::BigIntUnsigned);
1426impl_mysql_sql_type_to_rust!(f32 => drizzle_types::mysql::types::Float);
1427impl_mysql_sql_type_to_rust!(f64 => drizzle_types::mysql::types::Double);
1428impl_mysql_sql_type_to_rust!(bool => drizzle_types::mysql::types::Boolean);
1429impl_mysql_sql_type_to_rust!(crate::prelude::String =>
1430    drizzle_types::mysql::types::Char,
1431    drizzle_types::mysql::types::Varchar,
1432    drizzle_types::mysql::types::TinyText,
1433    drizzle_types::mysql::types::Text,
1434    drizzle_types::mysql::types::MediumText,
1435    drizzle_types::mysql::types::LongText,
1436    drizzle_types::mysql::types::Enum,
1437    drizzle_types::mysql::types::Set,
1438    drizzle_types::mysql::types::Any,
1439);
1440impl_mysql_sql_type_to_rust!(crate::prelude::Vec<u8> =>
1441    drizzle_types::mysql::types::Binary,
1442    drizzle_types::mysql::types::Varbinary,
1443    drizzle_types::mysql::types::TinyBlob,
1444    drizzle_types::mysql::types::Blob,
1445    drizzle_types::mysql::types::MediumBlob,
1446    drizzle_types::mysql::types::LongBlob,
1447    drizzle_types::mysql::types::Bit,
1448);
1449impl_mysql_sql_type_to_rust!(u16 => drizzle_types::mysql::types::Year);
1450
1451#[cfg(feature = "rust-decimal")]
1452impl_mysql_sql_type_to_rust!(rust_decimal::Decimal => drizzle_types::mysql::types::Decimal);
1453#[cfg(not(feature = "rust-decimal"))]
1454impl_mysql_sql_type_to_rust!(crate::prelude::String => drizzle_types::mysql::types::Decimal);
1455
1456#[cfg(feature = "serde")]
1457impl_mysql_sql_type_to_rust!(serde_json::Value => drizzle_types::mysql::types::Json);
1458#[cfg(not(feature = "serde"))]
1459impl_mysql_sql_type_to_rust!(crate::prelude::String => drizzle_types::mysql::types::Json);
1460
1461#[cfg(feature = "chrono")]
1462impl_mysql_sql_type_to_rust!(chrono::NaiveDate => drizzle_types::mysql::types::Date);
1463#[cfg(all(not(feature = "chrono"), feature = "time"))]
1464impl_mysql_sql_type_to_rust!(time::Date => drizzle_types::mysql::types::Date);
1465#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1466impl_mysql_sql_type_to_rust!(jiff::civil::Date => drizzle_types::mysql::types::Date);
1467#[cfg(not(any(feature = "chrono", feature = "time", feature = "jiff")))]
1468impl_mysql_sql_type_to_rust!(crate::prelude::String => drizzle_types::mysql::types::Date);
1469
1470// Unlike SQL TIME in SQLite/PostgreSQL, MySQL TIME is a signed duration that
1471// can exceed 24 hours (up to 838:59:59). Clock-only chrono/time values cannot
1472// represent its full domain, so the canonical selected value remains text,
1473// matching Drizzle ORM's MySQL TIME mapping.
1474impl_mysql_sql_type_to_rust!(crate::prelude::String => drizzle_types::mysql::types::Time);
1475
1476#[cfg(feature = "chrono")]
1477impl_mysql_sql_type_to_rust!(chrono::NaiveDateTime => drizzle_types::mysql::types::DateTime);
1478// MySQL TIMESTAMP is session-time-zone aware. Wire adapters must establish a
1479// UTC session before executing typed queries, so the public value is an
1480// explicit UTC instant rather than an ambiguous naive datetime.
1481#[cfg(feature = "chrono")]
1482impl_mysql_sql_type_to_rust!(chrono::DateTime<chrono::Utc> => drizzle_types::mysql::types::Timestamp);
1483#[cfg(all(not(feature = "chrono"), feature = "time"))]
1484impl_mysql_sql_type_to_rust!(time::PrimitiveDateTime => drizzle_types::mysql::types::DateTime);
1485#[cfg(all(not(feature = "chrono"), feature = "time"))]
1486impl_mysql_sql_type_to_rust!(time::OffsetDateTime => drizzle_types::mysql::types::Timestamp);
1487#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1488impl_mysql_sql_type_to_rust!(jiff::civil::DateTime => drizzle_types::mysql::types::DateTime);
1489#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1490impl_mysql_sql_type_to_rust!(jiff::Timestamp => drizzle_types::mysql::types::Timestamp);
1491#[cfg(not(any(feature = "chrono", feature = "time", feature = "jiff")))]
1492impl_mysql_sql_type_to_rust!(crate::prelude::String =>
1493    drizzle_types::mysql::types::DateTime,
1494    drizzle_types::mysql::types::Timestamp,
1495);
1496
1497impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Int2 {
1498    type RustType = i16;
1499}
1500
1501impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Int4 {
1502    type RustType = i32;
1503}
1504
1505impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Int8 {
1506    type RustType = i64;
1507}
1508
1509impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Float4 {
1510    type RustType = f32;
1511}
1512
1513impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Float8 {
1514    type RustType = f64;
1515}
1516
1517impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Varchar {
1518    type RustType = crate::prelude::String;
1519}
1520
1521impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Text {
1522    type RustType = crate::prelude::String;
1523}
1524
1525impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Char {
1526    type RustType = crate::prelude::String;
1527}
1528
1529impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Bytea {
1530    type RustType = crate::prelude::Vec<u8>;
1531}
1532
1533impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Boolean {
1534    type RustType = bool;
1535}
1536
1537#[cfg(feature = "rust-decimal")]
1538impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Numeric {
1539    type RustType = rust_decimal::Decimal;
1540}
1541
1542#[cfg(not(feature = "rust-decimal"))]
1543impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Numeric {
1544    type RustType = crate::prelude::String;
1545}
1546
1547impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Any {
1548    type RustType = crate::prelude::String;
1549}
1550
1551#[cfg(feature = "chrono")]
1552impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamptz {
1553    type RustType = chrono::DateTime<chrono::Utc>;
1554}
1555
1556#[cfg(feature = "chrono")]
1557impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamp {
1558    type RustType = chrono::NaiveDateTime;
1559}
1560
1561#[cfg(feature = "chrono")]
1562impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Date {
1563    type RustType = chrono::NaiveDate;
1564}
1565
1566#[cfg(feature = "chrono")]
1567impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Time {
1568    type RustType = chrono::NaiveTime;
1569}
1570
1571#[cfg(feature = "chrono")]
1572impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timetz {
1573    type RustType = chrono::NaiveTime;
1574}
1575
1576#[cfg(all(not(feature = "chrono"), feature = "time"))]
1577impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamptz {
1578    type RustType = time::OffsetDateTime;
1579}
1580
1581#[cfg(all(not(feature = "chrono"), feature = "time"))]
1582impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamp {
1583    type RustType = time::PrimitiveDateTime;
1584}
1585
1586#[cfg(all(not(feature = "chrono"), feature = "time"))]
1587impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Date {
1588    type RustType = time::Date;
1589}
1590
1591#[cfg(all(not(feature = "chrono"), feature = "time"))]
1592impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Time {
1593    type RustType = time::Time;
1594}
1595
1596#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1597impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamptz {
1598    type RustType = jiff::Timestamp;
1599}
1600
1601#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1602impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamp {
1603    type RustType = jiff::civil::DateTime;
1604}
1605
1606#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1607impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Date {
1608    type RustType = jiff::civil::Date;
1609}
1610
1611#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1612impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Time {
1613    type RustType = jiff::civil::Time;
1614}
1615
1616#[cfg(feature = "uuid")]
1617impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Uuid {
1618    type RustType = uuid::Uuid;
1619}
1620
1621#[cfg(feature = "serde")]
1622impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Json {
1623    type RustType = serde_json::Value;
1624}
1625
1626#[cfg(feature = "serde")]
1627impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Jsonb {
1628    type RustType = serde_json::Value;
1629}
1630
1631// -- Feature-gated type marker mappings --
1632
1633#[cfg(feature = "chrono")]
1634impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Interval {
1635    type RustType = chrono::Duration;
1636}
1637
1638#[cfg(not(feature = "chrono"))]
1639impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Interval {
1640    type RustType = crate::prelude::String;
1641}
1642
1643#[cfg(feature = "cidr")]
1644impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Inet {
1645    type RustType = cidr::IpInet;
1646}
1647
1648#[cfg(not(feature = "cidr"))]
1649impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Inet {
1650    type RustType = crate::prelude::String;
1651}
1652
1653#[cfg(feature = "cidr")]
1654impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Cidr {
1655    type RustType = cidr::IpCidr;
1656}
1657
1658#[cfg(not(feature = "cidr"))]
1659impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Cidr {
1660    type RustType = crate::prelude::String;
1661}
1662
1663impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::MacAddr {
1664    type RustType = crate::prelude::String;
1665}
1666
1667impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::MacAddr8 {
1668    type RustType = crate::prelude::String;
1669}
1670
1671#[cfg(feature = "geo-types")]
1672impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Point {
1673    type RustType = geo_types::Point<f64>;
1674}
1675
1676#[cfg(not(feature = "geo-types"))]
1677impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Point {
1678    type RustType = crate::prelude::String;
1679}
1680
1681#[cfg(feature = "geo-types")]
1682impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::LineString {
1683    type RustType = geo_types::LineString<f64>;
1684}
1685
1686#[cfg(not(feature = "geo-types"))]
1687impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::LineString {
1688    type RustType = crate::prelude::String;
1689}
1690
1691#[cfg(feature = "geo-types")]
1692impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Rect {
1693    type RustType = geo_types::Rect<f64>;
1694}
1695
1696#[cfg(not(feature = "geo-types"))]
1697impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Rect {
1698    type RustType = crate::prelude::String;
1699}
1700
1701#[cfg(feature = "bit-vec")]
1702impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::BitString {
1703    type RustType = bit_vec::BitVec;
1704}
1705
1706#[cfg(not(feature = "bit-vec"))]
1707impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::BitString {
1708    type RustType = crate::prelude::String;
1709}
1710
1711impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Line {
1712    type RustType = crate::prelude::String;
1713}
1714
1715impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::LineSegment {
1716    type RustType = crate::prelude::String;
1717}
1718
1719impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Polygon {
1720    type RustType = crate::prelude::String;
1721}
1722
1723impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Circle {
1724    type RustType = crate::prelude::String;
1725}
1726
1727impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Enum {
1728    type RustType = crate::prelude::String;
1729}
1730
1731// =============================================================================
1732// WrapNullable — Option<T> wrapping based on nullability
1733// =============================================================================
1734
1735/// `T` for [`NonNull`](crate::expr::NonNull), `Option<T>` for
1736/// [`Null`](crate::expr::Null).
1737pub trait WrapNullable<T> {
1738    /// The wrapped type.
1739    type Output;
1740}
1741
1742impl<T> WrapNullable<T> for crate::expr::NonNull {
1743    type Output = T;
1744}
1745
1746impl<T> WrapNullable<T> for crate::expr::Null {
1747    type Output = Option<T>;
1748}
1749
1750// =============================================================================
1751// ExprValueType — "what Rust type does this expression produce?"
1752// =============================================================================
1753
1754/// The Rust type a selected column or typed expression decodes into.
1755///
1756/// Implemented for:
1757/// - columns (generated by the table macros);
1758/// - `SQLExpr<V, T, N, A, S>`: [`SQLTypeToRust`] of `T`, wrapped in `Option`
1759///   when `N` is [`Null`](crate::expr::Null);
1760/// - raw `SQL<'a, V>`: `()`, so the caller must name the row type
1761///   (`.all::<T>()`).
1762#[diagnostic::on_unimplemented(
1763    message = "cannot infer Rust type for expression `{Self}`",
1764    label = "use typed expressions or derive FromRow to specify the Rust type",
1765    note = "raw SQL and JSON expressions require explicit type annotation"
1766)]
1767pub trait ExprValueType {
1768    /// The decoded Rust type.
1769    type ValueType;
1770}
1771
1772impl<T: ExprValueType + ?Sized> ExprValueType for &T {
1773    type ValueType = T::ValueType;
1774}
1775
1776impl<V: crate::SQLParam, T, N, A, S> ExprValueType for crate::expr::SQLExpr<'_, V, T, N, A, S>
1777where
1778    T: crate::types::DataType + SQLTypeToRust<V::DialectMarker>,
1779    N: crate::expr::Nullability + WrapNullable<<T as SQLTypeToRust<V::DialectMarker>>::RustType>,
1780    A: crate::expr::AggregateKind,
1781{
1782    type ValueType = <N as WrapNullable<<T as SQLTypeToRust<V::DialectMarker>>::RustType>>::Output;
1783}
1784
1785/// Raw SQL has no known type (`()`); the caller must name the row type.
1786impl<V: crate::SQLParam> ExprValueType for crate::sql::SQL<'_, V> {
1787    type ValueType = ();
1788}
1789
1790// =============================================================================
1791// HasSelectModel — table → Select model (lifetime-free)
1792// =============================================================================
1793
1794/// The select model and column count of a table.
1795///
1796/// Generated by `#[SQLiteTable]`, `#[PostgresTable]` and `#[MySQLTable]`.
1797/// `SELECT *` from the table decodes into `SelectModel`.
1798#[diagnostic::on_unimplemented(
1799    message = "`{Self}` is not a drizzle table",
1800    label = "ensure this type was derived with #[SQLiteTable], #[PostgresTable], or #[MySQLTable]"
1801)]
1802pub trait HasSelectModel {
1803    /// The struct a `SELECT *` row decodes into.
1804    type SelectModel;
1805    /// Number of columns in the table.
1806    const COLUMN_COUNT: usize;
1807}
1808
1809impl<T: HasSelectModel + ?Sized> HasSelectModel for &T {
1810    type SelectModel = T::SelectModel;
1811
1812    const COLUMN_COUNT: usize = T::COLUMN_COUNT;
1813}
1814
1815// =============================================================================
1816// ResolveRow — Marker + Table → default row type R
1817// =============================================================================
1818
1819/// The row type a select marker produces when selecting from `Table`.
1820///
1821/// Computed at `.from(table)`: the table's select model for `SELECT *`, a
1822/// tuple of value types for explicit columns, `R` for `SelectAs<R>`, and
1823/// `()` for raw SQL.
1824#[diagnostic::on_unimplemented(
1825    message = "cannot resolve return type for this query",
1826    label = "the selected columns and table do not produce a known row type"
1827)]
1828pub trait ResolveRow<Table> {
1829    /// The inferred row type.
1830    type Row;
1831}
1832
1833impl<T: HasSelectModel> ResolveRow<T> for SelectStar {
1834    type Row = T::SelectModel;
1835}
1836
1837impl<T> ResolveRow<T> for SelectExpr {
1838    type Row = ();
1839}
1840
1841impl<R, T> ResolveRow<T> for SelectAs<R>
1842where
1843    R: SelectAsFrom<T>,
1844{
1845    type Row = R;
1846}
1847
1848impl<M, Scope, Used, T> ResolveRow<T> for Scoped<M, Scope, Used>
1849where
1850    M: ResolveRow<T>,
1851{
1852    type Row = M::Row;
1853}
1854
1855/// The `FromRow` struct `Self` may select from `Table`.
1856///
1857/// Checked by `.select(MyRow::Select).from(table)`. `#[from(Table)]` on a
1858/// `FromRow` struct implements this for that table only. A struct without
1859/// `#[from(...)]` accepts any table.
1860#[diagnostic::on_unimplemented(
1861    message = "row selector `{Self}` cannot be used with table `{Table}`",
1862    label = "the #[from(...)] table does not match .from(...)",
1863    note = "set #[from(TheTable)] to the same table passed to .from(...)"
1864)]
1865pub trait SelectAsFrom<Table> {}
1866
1867// -- SelectCols: column value types → row tuple --
1868
1869macro_rules! impl_resolve_row_cols {
1870    ($($T:ident),+; $($idx:tt),+) => {
1871        impl<__Table, $($T: ExprValueType),+> ResolveRow<__Table> for SelectCols<($($T,)+)> {
1872            type Row = ($(<$T as ExprValueType>::ValueType,)+);
1873        }
1874    };
1875}
1876
1877with_col_sizes_8!(impl_resolve_row_cols);
1878
1879#[cfg(any(
1880    feature = "col16",
1881    feature = "col32",
1882    feature = "col64",
1883    feature = "col128",
1884    feature = "col200"
1885))]
1886with_col_sizes_16!(impl_resolve_row_cols);
1887
1888#[cfg(any(
1889    feature = "col32",
1890    feature = "col64",
1891    feature = "col128",
1892    feature = "col200"
1893))]
1894with_col_sizes_32!(impl_resolve_row_cols);
1895
1896#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1897with_col_sizes_64!(impl_resolve_row_cols);
1898
1899#[cfg(any(feature = "col128", feature = "col200"))]
1900with_col_sizes_128!(impl_resolve_row_cols);
1901
1902#[cfg(feature = "col200")]
1903with_col_sizes_200!(impl_resolve_row_cols);
1904
1905macro_rules! selected_columns_cons {
1906    () => {
1907        crate::Nil
1908    };
1909    ($head:ident $(, $tail:ident)*) => {
1910        crate::Cons<<$head as ExprValueType>::ValueType, selected_columns_cons!($($tail),*)>
1911    };
1912}
1913
1914macro_rules! selected_expressions_cons {
1915    () => {
1916        crate::Nil
1917    };
1918    ($head:ident $(, $tail:ident)*) => {
1919        crate::Cons<$head, selected_expressions_cons!($($tail),*)>
1920    };
1921}
1922
1923macro_rules! impl_selected_column_list_tuple {
1924    ($($T:ident),+; $($idx:tt),+) => {
1925        impl<$($T: ExprValueType),+> SelectedColumnList for ($($T,)+) {
1926            type Columns = selected_columns_cons!($($T),+);
1927        }
1928    };
1929}
1930
1931macro_rules! impl_selected_expression_list_tuple {
1932    ($($T:ident),+; $($idx:tt),+) => {
1933        impl<$($T),+> SelectedExpressionList for ($($T,)+) {
1934            type Expressions = selected_expressions_cons!($($T),+);
1935        }
1936    };
1937}
1938
1939with_col_sizes_8!(impl_selected_column_list_tuple);
1940with_col_sizes_8!(impl_selected_expression_list_tuple);
1941
1942#[cfg(any(
1943    feature = "col16",
1944    feature = "col32",
1945    feature = "col64",
1946    feature = "col128",
1947    feature = "col200"
1948))]
1949with_col_sizes_16!(impl_selected_column_list_tuple);
1950#[cfg(any(
1951    feature = "col16",
1952    feature = "col32",
1953    feature = "col64",
1954    feature = "col128",
1955    feature = "col200"
1956))]
1957with_col_sizes_16!(impl_selected_expression_list_tuple);
1958
1959#[cfg(any(
1960    feature = "col32",
1961    feature = "col64",
1962    feature = "col128",
1963    feature = "col200"
1964))]
1965with_col_sizes_32!(impl_selected_column_list_tuple);
1966#[cfg(any(
1967    feature = "col32",
1968    feature = "col64",
1969    feature = "col128",
1970    feature = "col200"
1971))]
1972with_col_sizes_32!(impl_selected_expression_list_tuple);
1973
1974#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1975with_col_sizes_64!(impl_selected_column_list_tuple);
1976#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1977with_col_sizes_64!(impl_selected_expression_list_tuple);
1978
1979#[cfg(any(feature = "col128", feature = "col200"))]
1980with_col_sizes_128!(impl_selected_column_list_tuple);
1981#[cfg(any(feature = "col128", feature = "col200"))]
1982with_col_sizes_128!(impl_selected_expression_list_tuple);
1983
1984#[cfg(feature = "col200")]
1985with_col_sizes_200!(impl_selected_column_list_tuple);
1986#[cfg(feature = "col200")]
1987with_col_sizes_200!(impl_selected_expression_list_tuple);
1988
1989// =============================================================================
1990// JoinRow — how joins transform the row type
1991// =============================================================================
1992
1993use crate::scope::{FullJoin, InnerJoin, JoinRow, LeftJoin, RightJoin};
1994
1995// LATERAL joins grow `SELECT *` rows like their plain kind.
1996impl<R, T, Kind> JoinRow<R, T, crate::scope::Lateral<Kind>> for SelectStar
1997where
1998    SelectStar: JoinRow<R, T, Kind>,
1999{
2000    type Row = <SelectStar as JoinRow<R, T, Kind>>::Row;
2001}
2002
2003/// Selections that stay valid after a `LEFT JOIN LATERAL`.
2004///
2005/// `SELECT *` decodes the joined source as `Option<JoinedTable::SelectModel>`.
2006/// Explicit columns and `FromRow` selections are accepted only when they read
2007/// sources already in scope before the lateral join: a column of the lateral
2008/// source would have to become nullable on unmatched rows.
2009#[doc(hidden)]
2010pub trait LeftLateralSelection<Proof = ()>: left_lateral_private::Sealed {}
2011
2012mod left_lateral_private {
2013    pub trait Sealed {}
2014
2015    impl Sealed for super::SelectStar {}
2016    impl<Scope, Used> Sealed for super::Scoped<super::SelectStar, Scope, Used> {}
2017    impl<Columns, Scope, Used> Sealed for super::Scoped<super::SelectCols<Columns>, Scope, Used> {}
2018    impl<Row, Scope, Used> Sealed for super::Scoped<super::SelectAs<Row>, Scope, Used> {}
2019}
2020
2021impl LeftLateralSelection for SelectStar {}
2022impl<Scope, Used> LeftLateralSelection for Scoped<SelectStar, Scope, Used> {}
2023
2024impl<Columns, Scope, Used, Proof> LeftLateralSelection<Proof>
2025    for Scoped<SelectCols<Columns>, Scope, Used>
2026where
2027    Columns: SelectedExpressionList,
2028    Columns::Expressions: ProjectionIn<Scope, Proof>,
2029{
2030}
2031
2032impl<Row, Scope, Used, Proof> LeftLateralSelection<Proof> for Scoped<SelectAs<Row>, Scope, Used>
2033where
2034    Row: SelectTableFields,
2035    Row::TableFields: TableFieldsIn<Scope, Proof>,
2036{
2037}
2038
2039/// `SELECT *` + JOIN → `(CurrentRow, JoinedTable::SelectModel)`.
2040impl<R, T: HasSelectModel> JoinRow<R, T, InnerJoin> for SelectStar {
2041    type Row = (R, T::SelectModel);
2042}
2043
2044/// `SELECT *` + LEFT JOIN → `(CurrentRow, Option<JoinedTable::SelectModel>)`.
2045impl<R, T: HasSelectModel> JoinRow<R, T, LeftJoin> for SelectStar {
2046    type Row = (R, Option<T::SelectModel>);
2047}
2048
2049/// `SELECT *` + RIGHT JOIN → `(Option<CurrentRow>, JoinedTable::SelectModel)`.
2050impl<R, T: HasSelectModel> JoinRow<R, T, RightJoin> for SelectStar {
2051    type Row = (Option<R>, T::SelectModel);
2052}
2053
2054/// `SELECT *` + FULL JOIN → `(Option<CurrentRow>, Option<JoinedTable::SelectModel>)`.
2055impl<R, T: HasSelectModel> JoinRow<R, T, FullJoin> for SelectStar {
2056    type Row = (Option<R>, Option<T::SelectModel>);
2057}
2058
2059/// Explicit columns + JOIN → R unchanged.
2060impl<Cols, R, T, Kind> JoinRow<R, T, Kind> for SelectCols<Cols> {
2061    type Row = R;
2062}
2063
2064/// Raw/untyped + JOIN → R unchanged.
2065impl<R, T, Kind> JoinRow<R, T, Kind> for SelectExpr {
2066    type Row = R;
2067}
2068
2069/// Explicit model + JOIN → R unchanged.
2070impl<Row, R, T, Kind> JoinRow<R, T, Kind> for SelectAs<Row> {
2071    type Row = R;
2072}
2073
2074// =============================================================================
2075// IntoSelectTarget — select arguments → Marker type
2076// =============================================================================
2077
2078/// Something that can be passed to `.select(...)`; picks the select marker.
2079///
2080/// The marker decides how the row type is inferred:
2081/// - [`SelectStar`]: the table's select model;
2082/// - [`SelectCols<C>`]: a tuple of the columns' value types;
2083/// - [`SelectExpr`]: the caller names the row type;
2084/// - [`SelectAs<R>`]: the `FromRow` struct `R`.
2085///
2086/// Implemented for:
2087/// - `()` -> `SelectStar`
2088/// - `SQL<'a, V>` -> `SelectExpr`
2089/// - `SQLExpr<'a, V, T, N, A, S>` -> `SelectCols<(Self,)>`
2090/// - tuples `(A, B, ...)` -> `SelectCols<(A, B, ...)>`
2091/// - columns and tables (generated by the table macros)
2092/// - `FromRow` selectors (generated by the `FromRow` derives) -> `SelectAs<R>`
2093#[diagnostic::on_unimplemented(
2094    message = "`{Self}` cannot be used as a select target",
2095    label = "this type does not implement IntoSelectTarget",
2096    note = "implement IntoSelectTarget or use a column, table, or typed expression"
2097)]
2098pub trait IntoSelectTarget {
2099    /// The select marker.
2100    type Marker;
2101}
2102
2103impl<T: IntoSelectTarget + ?Sized> IntoSelectTarget for &T {
2104    type Marker = T::Marker;
2105}
2106
2107/// `select(())` → `SelectStar` — infer row type from the table.
2108impl IntoSelectTarget for () {
2109    type Marker = SelectStar;
2110}
2111
2112/// `select(sql!(...))` → `SelectExpr` — user must specify row type.
2113impl<V: crate::SQLParam> IntoSelectTarget for crate::sql::SQL<'_, V> {
2114    type Marker = SelectExpr;
2115}
2116
2117/// `select(typed_expr)` → `SelectCols<(Expr,)>` — single typed expression.
2118impl<V: crate::SQLParam, T, N, A, S> IntoSelectTarget for crate::expr::SQLExpr<'_, V, T, N, A, S>
2119where
2120    T: crate::types::DataType,
2121    N: crate::expr::Nullability,
2122    A: crate::expr::AggregateKind,
2123{
2124    type Marker = SelectCols<(Self,)>;
2125}
2126
2127/// Tuples of select targets → `SelectCols<(A, B, ...)>`.
2128macro_rules! impl_into_select_target_tuple {
2129    ($($T:ident),+; $($idx:tt),+) => {
2130        impl<$($T),+> IntoSelectTarget for ($($T,)+) {
2131            type Marker = SelectCols<($($T,)+)>;
2132        }
2133    };
2134}
2135
2136with_col_sizes_8!(impl_into_select_target_tuple);
2137
2138#[cfg(any(
2139    feature = "col16",
2140    feature = "col32",
2141    feature = "col64",
2142    feature = "col128",
2143    feature = "col200"
2144))]
2145with_col_sizes_16!(impl_into_select_target_tuple);
2146
2147#[cfg(any(
2148    feature = "col32",
2149    feature = "col64",
2150    feature = "col128",
2151    feature = "col200"
2152))]
2153with_col_sizes_32!(impl_into_select_target_tuple);
2154
2155#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
2156with_col_sizes_64!(impl_into_select_target_tuple);
2157
2158#[cfg(any(feature = "col128", feature = "col200"))]
2159with_col_sizes_128!(impl_into_select_target_tuple);
2160
2161#[cfg(feature = "col200")]
2162with_col_sizes_200!(impl_into_select_target_tuple);