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.
467pub trait SingleColGroupCheck<Grouped, Proof> {}
468
469/// The column an expression is matched as when checking GROUP BY.
470///
471/// An aliased column (`AliasedExpr<Col>`) matches as `Col`; a bare column or
472/// any other expression matches as itself.
473pub trait GroupByIdentity {
474    /// The type looked up in the grouped column list.
475    type Identity;
476}
477
478// Default: identity is self (bare column ZSTs)
479// (implemented by proc macros for each column ZST)
480
481// AliasedExpr unwraps to inner
482impl<E: GroupByIdentity> GroupByIdentity for crate::expr::AliasedExpr<E> {
483    type Identity = E::Identity;
484}
485
486// SQLExpr: identity is self (for aggregate expressions, this won't be checked anyway)
487impl<V: crate::SQLParam, T, N, A, S> GroupByIdentity for crate::expr::SQLExpr<'_, V, T, N, A, S>
488where
489    T: crate::types::DataType,
490    N: crate::expr::Nullability,
491    A: crate::expr::AggregateKind,
492{
493    type Identity = Self;
494}
495
496// ColumnBinOp: identity is self (complex expressions won't match GROUP BY)
497impl<Lhs, Rhs, Op, D, SQLType, Nullable> GroupByIdentity
498    for crate::expr::ColumnBinOp<Lhs, Rhs, Op, D, SQLType, Nullable>
499{
500    type Identity = Self;
501}
502
503// ColumnNeg: identity is self
504impl<T, D, SQLType, Nullable> GroupByIdentity for crate::expr::ColumnNeg<T, D, SQLType, Nullable> {
505    type Identity = Self;
506}
507
508// Aggregate expressions → always OK
509impl<E, Grouped> SingleColGroupCheck<Grouped, AggSkip> for E where
510    E: crate::expr::HasAggStatus<Status = crate::expr::AllAgg>
511{
512}
513
514// Scalar expressions → base column identity must be in Grouped list
515impl<E, Grouped, W> SingleColGroupCheck<Grouped, ScalarCheck<W>> for E
516where
517    E: crate::expr::HasAggStatus<Status = crate::expr::AllScalar> + GroupByIdentity,
518    Grouped: crate::scope::ListContains<E::Identity, W>,
519{
520}
521
522// Scalar expressions under a primary-key group → the whole row of that table
523// is functionally dependent on the group key, so any column of the grouped
524// table passes. No overlap with the `ScalarCheck` impl above: `PkGroup<T>`
525// never implements `ListContains`.
526impl<E, T> SingleColGroupCheck<PkGroup<T>, PkDependent> for E
527where
528    E: crate::expr::HasAggStatus<Status = crate::expr::AllScalar> + GroupByIdentity,
529    E::Identity: crate::traits::ColumnOf<T>,
530{
531}
532
533// N-tuple: check head element, recurse on tail
534// Uses (HeadProof, TailProof) witness structure, like ListIncludes.
535
536// 2-tuple
537impl<T0, T1, Grouped, P0, P1> ScalarColumnsIn<Grouped, (P0, P1)> for (T0, T1)
538where
539    T0: SingleColGroupCheck<Grouped, P0>,
540    T1: SingleColGroupCheck<Grouped, P1>,
541{
542}
543
544// 3+ tuples: check head, recurse on (T1, T2, ...)
545macro_rules! impl_scalar_columns_in {
546    // 1-tuple: skip (handled above directly)
547    ($T0:ident; $i0:tt) => {};
548    // 2-tuple: skip (handled above directly)
549    ($T0:ident, $T1:ident; $i0:tt, $i1:tt) => {};
550    // 3+ tuples: head + tail recursion
551    ($T0:ident, $($rest:ident),+; $i0:tt, $($ri:tt),+) => {
552        impl<$T0, $($rest),+, Grouped, HeadProof, TailProof>
553            ScalarColumnsIn<Grouped, (HeadProof, TailProof)>
554            for ($T0, $($rest),+)
555        where
556            $T0: SingleColGroupCheck<Grouped, HeadProof>,
557            ($($rest,)+): ScalarColumnsIn<Grouped, TailProof>,
558        {}
559    };
560}
561
562with_col_sizes_8!(impl_scalar_columns_in);
563
564#[cfg(any(
565    feature = "col16",
566    feature = "col32",
567    feature = "col64",
568    feature = "col128",
569    feature = "col200"
570))]
571with_col_sizes_16!(impl_scalar_columns_in);
572
573// =============================================================================
574// MarkerAggValidFor — top-level bound on terminal methods
575// =============================================================================
576
577/// The SELECT list is valid for the query's GROUP BY.
578///
579/// `.all()`, `.get()` and `.rows()` require this bound.
580///
581/// - `Grouped = ()` (no GROUP BY): any mix of columns is accepted.
582/// - `Grouped = Cons<...>`: each non-aggregate column of an explicit SELECT
583///   list must be in the list.
584/// - `Grouped = PkGroup<T>`: each non-aggregate column must belong to `T`.
585///
586/// `SELECT *`, raw SQL and `FromRow` selections are not checked.
587#[diagnostic::on_unimplemented(
588    message = "non-aggregate column in SELECT is not in GROUP BY",
589    label = "add this column to .group_by(...) or wrap it in an aggregate function"
590)]
591pub trait MarkerAggValidFor<Grouped, Proof = ()> {}
592
593// No GROUP BY (Grouped = ()) → always valid, any mix is fine
594impl<Mk> MarkerAggValidFor<()> for Mk {}
595
596// SelectStar with GROUP BY: can't check at compile time, always passes
597impl<Scope, Used, Head, Tail> MarkerAggValidFor<Cons<Head, Tail>>
598    for Scoped<SelectStar, Scope, Used>
599{
600}
601
602// SelectExpr with GROUP BY: can't check, always passes
603impl<Scope, Used, Head, Tail> MarkerAggValidFor<Cons<Head, Tail>>
604    for Scoped<SelectExpr, Scope, Used>
605{
606}
607
608// SelectAs with GROUP BY: user-specified type, always passes
609impl<Scope, Used, R, Head, Tail> MarkerAggValidFor<Cons<Head, Tail>>
610    for Scoped<SelectAs<R>, Scope, Used>
611{
612}
613
614// SelectCols with GROUP BY: check each scalar column is in the Grouped list
615impl<Scope, Used, Cols, Head, Tail, Proof> MarkerAggValidFor<Cons<Head, Tail>, Proof>
616    for Scoped<SelectCols<Cols>, Scope, Used>
617where
618    Cols: ScalarColumnsIn<Cons<Head, Tail>, Proof>,
619{
620}
621
622// GROUP BY a table's primary key (`Grouped = PkGroup<T>`): same shape as the
623// Cons impls above, but scalar columns are checked for membership in the
624// grouped table instead of the grouped column list.
625impl<Scope, Used, T> MarkerAggValidFor<PkGroup<T>> for Scoped<SelectStar, Scope, Used> {}
626
627impl<Scope, Used, T> MarkerAggValidFor<PkGroup<T>> for Scoped<SelectExpr, Scope, Used> {}
628
629impl<Scope, Used, R, T> MarkerAggValidFor<PkGroup<T>> for Scoped<SelectAs<R>, Scope, Used> {}
630
631impl<Scope, Used, Cols, T, Proof> MarkerAggValidFor<PkGroup<T>, Proof>
632    for Scoped<SelectCols<Cols>, Scope, Used>
633where
634    Cols: ScalarColumnsIn<PkGroup<T>, Proof>,
635{
636}
637
638// =============================================================================
639// Marker column-count validation for strict decode paths
640// =============================================================================
641
642/// The columns a decode target reads, as a type-level list.
643///
644/// Each column is one `Cons<T, ...>` node, where `T` is the Rust type it
645/// decodes into. Tuples concatenate their elements' lists.
646pub trait RowColumnList<Row: ?Sized> {
647    /// `Cons<T0, Cons<T1, ... Nil>>`.
648    type Columns: crate::TypeSet;
649}
650
651/// The value types of a selected column tuple, as a type-level list.
652pub trait SelectedColumnList {
653    /// `Cons<T0, Cons<T1, ... Nil>>`.
654    type Columns: crate::TypeSet;
655}
656
657/// Type-level expression list for an explicit SELECT projection.
658///
659/// Unlike [`SelectedColumnList`], this preserves each expression type so a
660/// dialect can validate SQL types and nullability at a later boundary such as
661/// `INSERT ... SELECT`.
662#[doc(hidden)]
663pub trait SelectedExpressionList {
664    type Expressions: crate::TypeSet;
665}
666
667trait SameType<T> {}
668impl<T> SameType<T> for T {}
669
670#[diagnostic::on_unimplemented(
671    message = "selected column decodes as `{Expected}`, but the decode target uses `{Actual}`",
672    label = "the decode target does not match the selected columns",
673    note = "a selected `MaybeNull<T>` can be NULL (an outer join or a nullable operand) \
674            and must be decoded as `Option<T>`"
675)]
676trait ColumnTypeCompatible<Row: ?Sized, Expected, Actual> {}
677
678impl<Row: ?Sized, T> ColumnTypeCompatible<Row, T, T> for () {}
679
680// A column from the nullable side of an outer join decodes only into `Option`.
681// The accepted inner types live on a separate trait so a decode error lists
682// one candidate here instead of every widened variant.
683impl<Row: ?Sized, Expected, Actual> ColumnTypeCompatible<Row, MaybeNull<Expected>, Option<Actual>>
684    for ()
685where
686    (): MaybeNullCompatible<Row, Expected, Actual>,
687{
688}
689
690/// Inner-type rule for [`MaybeNull`] columns: `Expected` is the column's
691/// own decoded type, `Actual` the type inside the target's `Option`.
692trait MaybeNullCompatible<Row: ?Sized, Expected, Actual> {}
693
694impl<Row: ?Sized, T> MaybeNullCompatible<Row, T, T> for () {}
695
696impl<Row: ?Sized, T> MaybeNullCompatible<Row, Option<T>, T> for () {}
697
698trait TypeListCompatible<Row: ?Sized, ActualList> {}
699
700impl<Row: ?Sized> TypeListCompatible<Row, Self> for crate::Nil {}
701
702impl<Row: ?Sized, EH, ET, AH, AT> TypeListCompatible<Row, crate::Cons<AH, AT>>
703    for crate::Cons<EH, ET>
704where
705    (): ColumnTypeCompatible<Row, EH, AH>,
706    ET: TypeListCompatible<Row, AT>,
707{
708}
709
710trait SqliteDecodeRow {}
711
712#[cfg(feature = "rusqlite")]
713impl SqliteDecodeRow for ::rusqlite::Row<'_> {}
714
715#[cfg(feature = "libsql")]
716impl SqliteDecodeRow for ::libsql::Row {}
717
718#[cfg(feature = "turso")]
719impl SqliteDecodeRow for ::turso::Row {}
720
721macro_rules! impl_sqlite_integer_decode_compat {
722    ($expected:ty => $($actual:ty),+ $(,)?) => {
723        $(
724            impl<Row> ColumnTypeCompatible<Row, $expected, $actual> for ()
725            where
726                Row: SqliteDecodeRow,
727            {
728            }
729        )+
730    };
731}
732
733impl_sqlite_integer_decode_compat!(
734    i64 => i8, i16, i32, isize, u8, u16, u32, u64, usize, bool
735);
736
737macro_rules! impl_sqlite_join_nullable_integer_decode_compat {
738    ($($actual:ty),+ $(,)?) => {
739        $(
740            impl<Row> MaybeNullCompatible<Row, i64, $actual> for ()
741            where
742                Row: SqliteDecodeRow,
743            {
744            }
745
746            impl<Row> MaybeNullCompatible<Row, Option<i64>, $actual> for ()
747            where
748                Row: SqliteDecodeRow,
749            {
750            }
751        )+
752    };
753}
754
755impl_sqlite_join_nullable_integer_decode_compat!(
756    i8, i16, i32, isize, u8, u16, u32, u64, usize, bool
757);
758
759impl_sqlite_integer_decode_compat!(
760    Option<i64> =>
761        Option<i8>,
762        Option<i16>,
763        Option<i32>,
764        Option<isize>,
765        Option<u8>,
766        Option<u16>,
767        Option<u32>,
768        Option<u64>,
769        Option<usize>,
770        Option<bool>
771);
772
773macro_rules! impl_row_column_list_one {
774    ($($ty:ty),+ $(,)?) => {
775        $(
776            impl<Row: ?Sized> RowColumnList<Row> for $ty {
777                type Columns = crate::Cons<$ty, crate::Nil>;
778            }
779        )+
780    };
781}
782
783impl_row_column_list_one!(
784    i8,
785    i16,
786    i32,
787    i64,
788    isize,
789    u8,
790    u16,
791    u32,
792    u64,
793    usize,
794    f32,
795    f64,
796    bool,
797    crate::prelude::String,
798    crate::prelude::Vec<u8>
799);
800
801impl<Row: ?Sized> RowColumnList<Row> for () {
802    type Columns = crate::Cons<(), crate::Nil>;
803}
804
805#[cfg(feature = "uuid")]
806impl<Row: ?Sized> RowColumnList<Row> for uuid::Uuid {
807    type Columns = crate::Cons<Self, crate::Nil>;
808}
809
810#[cfg(feature = "chrono")]
811impl<Row: ?Sized> RowColumnList<Row> for chrono::NaiveDate {
812    type Columns = crate::Cons<Self, crate::Nil>;
813}
814
815#[cfg(feature = "chrono")]
816impl<Row: ?Sized> RowColumnList<Row> for chrono::NaiveTime {
817    type Columns = crate::Cons<Self, crate::Nil>;
818}
819
820#[cfg(feature = "chrono")]
821impl<Row: ?Sized> RowColumnList<Row> for chrono::NaiveDateTime {
822    type Columns = crate::Cons<Self, crate::Nil>;
823}
824
825#[cfg(feature = "chrono")]
826impl<Row: ?Sized> RowColumnList<Row> for chrono::DateTime<chrono::Utc> {
827    type Columns = crate::Cons<Self, crate::Nil>;
828}
829
830#[cfg(feature = "serde")]
831impl<Row: ?Sized> RowColumnList<Row> for serde_json::Value {
832    type Columns = crate::Cons<Self, crate::Nil>;
833}
834
835#[cfg(feature = "rust-decimal")]
836impl<Row: ?Sized> RowColumnList<Row> for rust_decimal::Decimal {
837    type Columns = crate::Cons<Self, crate::Nil>;
838}
839
840#[cfg(feature = "chrono")]
841impl<Row: ?Sized> RowColumnList<Row> for chrono::Duration {
842    type Columns = crate::Cons<Self, crate::Nil>;
843}
844
845#[cfg(feature = "time")]
846impl<Row: ?Sized> RowColumnList<Row> for time::Date {
847    type Columns = crate::Cons<Self, crate::Nil>;
848}
849
850#[cfg(feature = "time")]
851impl<Row: ?Sized> RowColumnList<Row> for time::Time {
852    type Columns = crate::Cons<Self, crate::Nil>;
853}
854
855#[cfg(feature = "time")]
856impl<Row: ?Sized> RowColumnList<Row> for time::PrimitiveDateTime {
857    type Columns = crate::Cons<Self, crate::Nil>;
858}
859
860#[cfg(feature = "time")]
861impl<Row: ?Sized> RowColumnList<Row> for time::OffsetDateTime {
862    type Columns = crate::Cons<Self, crate::Nil>;
863}
864
865#[cfg(feature = "time")]
866impl<Row: ?Sized> RowColumnList<Row> for time::Duration {
867    type Columns = crate::Cons<Self, crate::Nil>;
868}
869
870#[cfg(feature = "jiff")]
871impl<Row: ?Sized> RowColumnList<Row> for jiff::civil::Date {
872    type Columns = crate::Cons<Self, crate::Nil>;
873}
874
875#[cfg(feature = "jiff")]
876impl<Row: ?Sized> RowColumnList<Row> for jiff::civil::Time {
877    type Columns = crate::Cons<Self, crate::Nil>;
878}
879
880#[cfg(feature = "jiff")]
881impl<Row: ?Sized> RowColumnList<Row> for jiff::civil::DateTime {
882    type Columns = crate::Cons<Self, crate::Nil>;
883}
884
885#[cfg(feature = "jiff")]
886impl<Row: ?Sized> RowColumnList<Row> for jiff::Timestamp {
887    type Columns = crate::Cons<Self, crate::Nil>;
888}
889
890#[cfg(feature = "cidr")]
891impl<Row: ?Sized> RowColumnList<Row> for cidr::IpInet {
892    type Columns = crate::Cons<Self, crate::Nil>;
893}
894
895#[cfg(feature = "cidr")]
896impl<Row: ?Sized> RowColumnList<Row> for cidr::IpCidr {
897    type Columns = crate::Cons<Self, crate::Nil>;
898}
899
900#[cfg(feature = "geo-types")]
901impl<Row: ?Sized> RowColumnList<Row> for geo_types::Point<f64> {
902    type Columns = crate::Cons<Self, crate::Nil>;
903}
904
905#[cfg(feature = "geo-types")]
906impl<Row: ?Sized> RowColumnList<Row> for geo_types::LineString<f64> {
907    type Columns = crate::Cons<Self, crate::Nil>;
908}
909
910#[cfg(feature = "geo-types")]
911impl<Row: ?Sized> RowColumnList<Row> for geo_types::Rect<f64> {
912    type Columns = crate::Cons<Self, crate::Nil>;
913}
914
915#[cfg(feature = "bit-vec")]
916impl<Row: ?Sized> RowColumnList<Row> for bit_vec::BitVec {
917    type Columns = crate::Cons<Self, crate::Nil>;
918}
919
920#[cfg(feature = "arrayvec")]
921impl<Row: ?Sized, const N: usize> RowColumnList<Row> for arrayvec::ArrayString<N> {
922    type Columns = crate::Cons<Self, crate::Nil>;
923}
924
925#[cfg(feature = "arrayvec")]
926impl<Row: ?Sized, T, const N: usize> RowColumnList<Row> for arrayvec::ArrayVec<T, N> {
927    type Columns = crate::Cons<Self, crate::Nil>;
928}
929
930impl<Row: ?Sized> RowColumnList<Row> for compact_str::CompactString {
931    type Columns = crate::Cons<Self, crate::Nil>;
932}
933
934#[cfg(feature = "bytes")]
935impl<Row: ?Sized> RowColumnList<Row> for bytes::Bytes {
936    type Columns = crate::Cons<Self, crate::Nil>;
937}
938
939#[cfg(feature = "bytes")]
940impl<Row: ?Sized> RowColumnList<Row> for bytes::BytesMut {
941    type Columns = crate::Cons<Self, crate::Nil>;
942}
943
944impl<Row: ?Sized, A: smallvec::Array> RowColumnList<Row> for smallvec::SmallVec<A> {
945    type Columns = crate::Cons<Self, crate::Nil>;
946}
947
948impl<Row: ?Sized, T> RowColumnList<Row> for Option<T> {
949    type Columns = crate::Cons<Self, crate::Nil>;
950}
951
952/// Helper: split last element from a type list and generate `RowColumnList` impl.
953/// Called by `impl_rcl_tuple` after separating first from rest.
954macro_rules! impl_rcl_body {
955    // 1-tuple: just delegate
956    ([$A:ident] []) => {
957        impl<Row: ?Sized, $A: RowColumnList<Row>> RowColumnList<Row> for ($A,) {
958            type Columns = <$A as RowColumnList<Row>>::Columns;
959        }
960    };
961    // N-tuple: delegate to (N-1)-tuple, concat last
962    ([$($all:ident),+] [$($prev:ident),+; $last:ident]) => {
963        impl<Row: ?Sized, $($all),+> RowColumnList<Row> for ($($all,)+)
964        where
965            $last: RowColumnList<Row>,
966            ($($prev,)+): RowColumnList<Row>,
967            <($($prev,)+) as RowColumnList<Row>>::Columns:
968                crate::Concat<<$last as RowColumnList<Row>>::Columns>,
969        {
970            type Columns = <<($($prev,)+) as RowColumnList<Row>>::Columns as crate::Concat<
971                <$last as RowColumnList<Row>>::Columns,
972            >>::Output;
973        }
974    };
975}
976
977/// Callback for `with_type_sizes_*!`: receives all types, separates last via
978/// recursive accumulator, then delegates to `impl_rcl_body`.
979macro_rules! impl_rcl_tuple {
980    ($($T:ident),+) => {
981        impl_rcl_split!([$($T),+] [] $($T),+);
982    };
983}
984
985/// Recursive accumulator to split `[all] [prev...] remaining...`
986macro_rules! impl_rcl_split {
987    // 1-tuple: no prev, single element
988    ([$A:ident] [] $only:ident) => {
989        impl_rcl_body!([$A] []);
990    };
991    // Base: one element left in remaining = it's the last
992    ([$($all:ident),+] [$($prev:ident),+] $last:ident) => {
993        impl_rcl_body!([$($all),+] [$($prev),+; $last]);
994    };
995    // Recurse from empty prev
996    ([$($all:ident),+] [] $head:ident, $($rest:ident),+) => {
997        impl_rcl_split!([$($all),+] [$head] $($rest),+);
998    };
999    // Recurse with non-empty prev
1000    ([$($all:ident),+] [$($prev:ident),+] $head:ident, $($rest:ident),+) => {
1001        impl_rcl_split!([$($all),+] [$($prev),+, $head] $($rest),+);
1002    };
1003}
1004
1005with_type_sizes_8!(impl_rcl_tuple);
1006
1007#[cfg(any(
1008    feature = "col16",
1009    feature = "col32",
1010    feature = "col64",
1011    feature = "col128",
1012    feature = "col200"
1013))]
1014with_type_sizes_16!(impl_rcl_tuple);
1015
1016#[cfg(any(
1017    feature = "col32",
1018    feature = "col64",
1019    feature = "col128",
1020    feature = "col200"
1021))]
1022with_type_sizes_32!(impl_rcl_tuple);
1023
1024/// The decode target `Actual` matches what the query selects.
1025///
1026/// `.all()`, `.get()` and `.rows()` require this bound. `Inferred` is the
1027/// query's inferred row type and `Actual` the type the caller decodes into.
1028///
1029/// - Explicit columns: each column of `Actual` must have the selected
1030///   column's type, and must be `Option` when an outer join or a nullable
1031///   operand can make it NULL.
1032/// - Joined `SELECT *`: `Actual` must keep the inferred shape (see
1033///   [`JoinedStarRow`]).
1034/// - Raw SQL: `Actual` must equal `Inferred`.
1035/// - Single-table `SELECT *` and `FromRow` selections are not checked here.
1036///
1037/// `Proof` is the same witness the terminal method infers for
1038/// [`MarkerScopeValidFor`], so outer-join nullability found while checking
1039/// scope also decides which decoded columns must be `Option`.
1040#[diagnostic::on_unimplemented(
1041    message = "selected shape does not match decode target `{Actual}`",
1042    label = "this decode target is not type-compatible with .select(...) output",
1043    note = "use typed expressions or derive FromRow for explicit remapping when selecting custom expressions"
1044)]
1045pub trait MarkerColumnCountValid<Row: ?Sized, Inferred, Actual, Proof = ()> {}
1046
1047/// The select marker can be decoded by `.all()` / `.get()` without an
1048/// explicit row type.
1049///
1050/// A raw `select(sql!(...))` is excluded on purpose: give it a type with a
1051/// typed expression (`raw_non_null`, `raw_nullable`) or select into a
1052/// `FromRow` struct instead.
1053#[diagnostic::on_unimplemented(
1054    message = "raw select expressions require explicit typing in strict decode",
1055    label = "`select(sql!(...)).all()/get()` is not allowed in strict mode",
1056    note = "use typed wrappers like `raw_non_null`/`raw_nullable` or derive FromRow"
1057)]
1058pub trait StrictDecodeMarker {}
1059
1060impl StrictDecodeMarker for SelectStar {}
1061impl<Cols> StrictDecodeMarker for SelectCols<Cols> {}
1062impl<R> StrictDecodeMarker for SelectAs<R> {}
1063impl<M, Scope, Used> StrictDecodeMarker for Scoped<M, Scope, Used> where M: StrictDecodeMarker {}
1064
1065impl<Row: ?Sized, Inferred, Actual, Proof> MarkerColumnCountValid<Row, Inferred, Actual, Proof>
1066    for SelectStar
1067{
1068}
1069
1070impl<Row: ?Sized, Cols, Inferred, Actual, Proof>
1071    MarkerColumnCountValid<Row, Inferred, Actual, Proof> for SelectCols<Cols>
1072where
1073    Cols: SelectedColumnList,
1074    Actual: RowColumnList<Row>,
1075    <Cols as SelectedColumnList>::Columns:
1076        TypeListCompatible<Row, <Actual as RowColumnList<Row>>::Columns>,
1077{
1078}
1079
1080impl<Row: ?Sized, Inferred, Actual, Proof> MarkerColumnCountValid<Row, Inferred, Actual, Proof>
1081    for SelectExpr
1082where
1083    Inferred: SameType<Actual>,
1084{
1085}
1086
1087impl<Row: ?Sized, R, Inferred, Actual, Proof> MarkerColumnCountValid<Row, Inferred, Actual, Proof>
1088    for SelectAs<R>
1089{
1090}
1091
1092/// Single-source `SELECT *`: the table model may be decoded into any row type.
1093impl<Row: ?Sized, Table, Used, Inferred, Actual, Proof>
1094    MarkerColumnCountValid<Row, Inferred, Actual, Proof>
1095    for Scoped<SelectStar, Cons<Table, Nil>, Used>
1096{
1097}
1098
1099/// Joined `SELECT *`: the decode target must keep the inferred row shape, with
1100/// `Option` on every source that an outer join can leave NULL.
1101impl<Row: ?Sized, First, Second, Rest, Used, Inferred, Actual, Proof>
1102    MarkerColumnCountValid<Row, Inferred, Actual, Proof>
1103    for Scoped<SelectStar, Cons<First, Cons<Second, Rest>>, Used>
1104where
1105    Inferred: JoinedStarRow<Actual>,
1106{
1107}
1108
1109impl<Row: ?Sized, Cols, Scope, Used, Inferred, Actual, UsedProof, ColsProof>
1110    MarkerColumnCountValid<Row, Inferred, Actual, (UsedProof, ColsProof)>
1111    for Scoped<SelectCols<Cols>, Scope, Used>
1112where
1113    Cols: SelectedExpressionList,
1114    Cols::Expressions: ProjectionIn<Scope, ColsProof>,
1115    Actual: RowColumnList<Row>,
1116    <Cols::Expressions as ProjectionIn<Scope, ColsProof>>::Columns:
1117        TypeListCompatible<Row, <Actual as RowColumnList<Row>>::Columns>,
1118{
1119}
1120
1121impl<Row: ?Sized, Scope, Used, Inferred, Actual, Proof>
1122    MarkerColumnCountValid<Row, Inferred, Actual, Proof> for Scoped<SelectExpr, Scope, Used>
1123where
1124    Inferred: SameType<Actual>,
1125{
1126}
1127
1128/// `FromRow` selectors are checked by [`MarkerScopeValidFor`].
1129impl<Row: ?Sized, R, Scope, Used, Inferred, Actual, Proof>
1130    MarkerColumnCountValid<Row, Inferred, Actual, Proof> for Scoped<SelectAs<R>, Scope, Used>
1131{
1132}
1133
1134/// Decode target for a joined `SELECT *` row.
1135///
1136/// Joins nest the inferred row as `(previous, joined)`. Each half must be
1137/// decoded as its inferred type; a half may additionally be widened to
1138/// `Option`, but a half the join already made `Option` cannot be narrowed.
1139#[diagnostic::on_unimplemented(
1140    message = "joined `SELECT *` rows decode as `{Self}`, not `{Actual}`",
1141    label = "the decode target does not match the joined row type",
1142    note = "LEFT/RIGHT/FULL JOIN sources can be NULL: decode them as `Option<_>`, \
1143            e.g. `(SelectUsers, Option<SelectPosts>)` after `.left_join(posts)`"
1144)]
1145pub trait JoinedStarRow<Actual> {}
1146
1147impl<A, B, ActualA, ActualB> JoinedStarRow<(ActualA, ActualB)> for (A, B)
1148where
1149    A: JoinedStarPart<ActualA>,
1150    B: JoinedStarPart<ActualB>,
1151{
1152}
1153
1154/// One half of a joined `SELECT *` row: exact, or widened to `Option`.
1155#[doc(hidden)]
1156#[diagnostic::on_unimplemented(
1157    message = "this half of the joined `SELECT *` row decodes as `{Self}`, not `{Actual}`",
1158    label = "the decode target does not match the joined row type",
1159    note = "LEFT/RIGHT/FULL JOIN sources can be NULL: decode them as `Option<_>`"
1160)]
1161pub trait JoinedStarPart<Actual> {}
1162
1163impl<T> JoinedStarPart<T> for T {}
1164
1165impl<T> JoinedStarPart<Option<T>> for T {}
1166
1167/// Decodes one result row into `R` the way the select marker `Self` asks.
1168///
1169/// `SelectAs<R>` uses `R: TryFrom<RowRef>` (the `FromRow` derive). Every
1170/// other marker uses [`FromDrizzleRow`].
1171pub trait DecodeSelectedRef<RowRef, R> {
1172    /// Decodes `row` into `R`.
1173    ///
1174    /// # Errors
1175    ///
1176    /// Returns an error if the row cannot be decoded into the expected type
1177    /// (missing columns, type mismatch, or downstream conversion failure).
1178    fn decode(row: RowRef) -> Result<R, DrizzleError>;
1179}
1180
1181impl<RowRef, R> DecodeSelectedRef<RowRef, R> for SelectAs<R>
1182where
1183    R: TryFrom<RowRef>,
1184    <R as TryFrom<RowRef>>::Error: Into<DrizzleError>,
1185{
1186    fn decode(row: RowRef) -> Result<R, DrizzleError> {
1187        R::try_from(row).map_err(Into::into)
1188    }
1189}
1190
1191impl<RowRef, R, M, Scope, Used> DecodeSelectedRef<RowRef, R> for Scoped<M, Scope, Used>
1192where
1193    M: DecodeSelectedRef<RowRef, R>,
1194{
1195    fn decode(row: RowRef) -> Result<R, DrizzleError> {
1196        M::decode(row)
1197    }
1198}
1199
1200impl<RowRef, Row: ?Sized, R> DecodeSelectedRef<RowRef, R> for SelectStar
1201where
1202    RowRef: core::ops::Deref<Target = Row>,
1203    R: FromDrizzleRow<Row>,
1204{
1205    fn decode(row: RowRef) -> Result<R, DrizzleError> {
1206        R::from_row(&*row)
1207    }
1208}
1209
1210impl<RowRef, Row: ?Sized, Cols, R> DecodeSelectedRef<RowRef, R> for SelectCols<Cols>
1211where
1212    RowRef: core::ops::Deref<Target = Row>,
1213    R: FromDrizzleRow<Row>,
1214{
1215    fn decode(row: RowRef) -> Result<R, DrizzleError> {
1216        R::from_row(&*row)
1217    }
1218}
1219
1220impl<RowRef, Row: ?Sized, R> DecodeSelectedRef<RowRef, R> for SelectExpr
1221where
1222    RowRef: core::ops::Deref<Target = Row>,
1223    R: FromDrizzleRow<Row>,
1224{
1225    fn decode(row: RowRef) -> Result<R, DrizzleError> {
1226        R::from_row(&*row)
1227    }
1228}
1229
1230// =============================================================================
1231// FromDrizzleRow — offset-based row extraction
1232// =============================================================================
1233
1234/// Reads a Rust value from a database row, starting at a column offset.
1235///
1236/// Unlike `TryFrom<Row>`, reading from an offset lets one joined row be split
1237/// across several model types. Tuples compose: `(A, B)` reads `A` at
1238/// `offset`, then `B` at `offset + A::COLUMN_COUNT`.
1239///
1240/// Implemented for scalar types per driver, for `Option<T>`, for tuples, and
1241/// by the `FromRow` derives and table macros for models.
1242#[diagnostic::on_unimplemented(
1243    message = "cannot deserialize `{Self}` from a database row",
1244    label = "this type does not implement FromDrizzleRow",
1245    note = "derive #[SQLiteFromRow], #[PostgresFromRow], or #[MySQLFromRow]"
1246)]
1247pub trait FromDrizzleRow<Row: ?Sized>: Sized {
1248    /// Number of columns this type reads from the row.
1249    const COLUMN_COUNT: usize;
1250
1251    /// Reads this type from `row`, starting at column `offset`.
1252    ///
1253    /// # Errors
1254    ///
1255    /// Returns an error if any column from `offset` through
1256    /// `offset + COLUMN_COUNT - 1` cannot be read or converted.
1257    fn from_row_at(row: &Row, offset: usize) -> Result<Self, DrizzleError>;
1258
1259    /// Reads this type from `row`, starting at column 0.
1260    ///
1261    /// # Errors
1262    ///
1263    /// Returns an error if the row cannot be decoded — see [`Self::from_row_at`].
1264    fn from_row(row: &Row) -> Result<Self, DrizzleError> {
1265        Self::from_row_at(row, 0)
1266    }
1267}
1268
1269/// A multi-column row type that can check whether it is absent (NULL).
1270///
1271/// This makes `Option<T>` work as a [`FromDrizzleRow`] target for a model,
1272/// as in a LEFT JOIN where the joined table may have no matching row.
1273///
1274/// The table macros implement this for each select model. Single-column
1275/// types (`i32`, `String`, ...) have their own `Option<T>` impls instead.
1276pub trait NullProbeRow<Row: ?Sized>: FromDrizzleRow<Row> {
1277    /// Returns `true` if the column at `offset` is NULL.
1278    ///
1279    /// # Errors
1280    ///
1281    /// Returns an error if the row cannot be inspected at `offset` (e.g. the
1282    /// driver reports an out-of-range index or conversion failure).
1283    fn is_null_at(row: &Row, offset: usize) -> Result<bool, DrizzleError>;
1284}
1285
1286// -- Tuple impls: generic over Row, composing inner impls --
1287
1288macro_rules! impl_from_drizzle_row_tuple {
1289    ($($T:ident),+; $($idx:tt),+) => {
1290        impl<__Row: ?Sized, $($T: FromDrizzleRow<__Row>),+> FromDrizzleRow<__Row> for ($($T,)+) {
1291            const COLUMN_COUNT: usize = 0 $(+ <$T as FromDrizzleRow<__Row>>::COLUMN_COUNT)+;
1292
1293            #[allow(non_snake_case)]
1294            fn from_row_at(
1295                row: &__Row,
1296                offset: usize,
1297            ) -> Result<Self, DrizzleError> {
1298                let mut __off = offset;
1299                $(
1300                    let $T = <$T as FromDrizzleRow<__Row>>::from_row_at(row, __off)?;
1301                    __off += <$T as FromDrizzleRow<__Row>>::COLUMN_COUNT;
1302                )+
1303                Ok(($($T,)+))
1304            }
1305        }
1306    };
1307}
1308
1309with_col_sizes_8!(impl_from_drizzle_row_tuple);
1310
1311#[cfg(any(
1312    feature = "col16",
1313    feature = "col32",
1314    feature = "col64",
1315    feature = "col128",
1316    feature = "col200"
1317))]
1318with_col_sizes_16!(impl_from_drizzle_row_tuple);
1319
1320#[cfg(any(
1321    feature = "col32",
1322    feature = "col64",
1323    feature = "col128",
1324    feature = "col200"
1325))]
1326with_col_sizes_32!(impl_from_drizzle_row_tuple);
1327
1328#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1329with_col_sizes_64!(impl_from_drizzle_row_tuple);
1330
1331#[cfg(any(feature = "col128", feature = "col200"))]
1332with_col_sizes_128!(impl_from_drizzle_row_tuple);
1333
1334#[cfg(feature = "col200")]
1335with_col_sizes_200!(impl_from_drizzle_row_tuple);
1336
1337// =============================================================================
1338// SQLTypeToRust — SQL type marker × dialect → canonical Rust type
1339// =============================================================================
1340
1341/// The default Rust type for a SQL type marker in dialect `D`.
1342///
1343/// `D` is a dialect marker ([`SQLiteDialect`], [`PostgresDialect`] or
1344/// [`MySQLDialect`]), so the mapping can differ per database. For example,
1345/// `postgres::types::Int4` maps to `i32` and `sqlite::types::Integer` to
1346/// `i64`. The selected column types of `.select(...)` come from here.
1347///
1348/// Some types map to a feature-gated Rust type (`chrono`, `time`, `jiff`,
1349/// `uuid`, `serde`, `cidr`, ...). Without any matching feature, some fall
1350/// back to `String`, while PostgreSQL date/time, `Uuid` and `Json`/`Jsonb`
1351/// have no mapping at all, which is a compile error naming the feature to
1352/// enable.
1353#[diagnostic::on_unimplemented(
1354    message = "SQL type `{Self}` has no default Rust mapping for dialect `{D}`",
1355    label = "this SQL type has no default Rust mapping for this dialect",
1356    note = "enable `chrono` for Date/Time/Timestamp/TimestampTz, `uuid` for Uuid, or `serde` for Json/Jsonb"
1357)]
1358pub trait SQLTypeToRust<D> {
1359    type RustType;
1360}
1361
1362// -- Dialect-native mappings ---------------------------------------------------
1363
1364use crate::dialect::{MySQLDialect, PostgresDialect, SQLiteDialect};
1365
1366impl<D, T> SQLTypeToRust<D> for crate::types::Array<T>
1367where
1368    T: crate::types::DataType + SQLTypeToRust<D>,
1369{
1370    type RustType = crate::prelude::Vec<<T as SQLTypeToRust<D>>::RustType>;
1371}
1372
1373impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Integer {
1374    type RustType = i64;
1375}
1376
1377impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Text {
1378    type RustType = crate::prelude::String;
1379}
1380
1381impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Real {
1382    type RustType = f64;
1383}
1384
1385impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Blob {
1386    type RustType = crate::prelude::Vec<u8>;
1387}
1388
1389impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Numeric {
1390    type RustType = f64;
1391}
1392
1393impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Any {
1394    type RustType = crate::prelude::String;
1395}
1396
1397macro_rules! impl_mysql_sql_type_to_rust {
1398    ($rust:ty => $($sql:ty),+ $(,)?) => {
1399        $(
1400            impl SQLTypeToRust<MySQLDialect> for $sql {
1401                type RustType = $rust;
1402            }
1403        )+
1404    };
1405}
1406
1407impl_mysql_sql_type_to_rust!(i8 => drizzle_types::mysql::types::TinyInt);
1408impl_mysql_sql_type_to_rust!(u8 => drizzle_types::mysql::types::TinyIntUnsigned);
1409impl_mysql_sql_type_to_rust!(i16 => drizzle_types::mysql::types::SmallInt);
1410impl_mysql_sql_type_to_rust!(u16 => drizzle_types::mysql::types::SmallIntUnsigned);
1411impl_mysql_sql_type_to_rust!(i32 =>
1412    drizzle_types::mysql::types::MediumInt,
1413    drizzle_types::mysql::types::Int,
1414);
1415impl_mysql_sql_type_to_rust!(u32 =>
1416    drizzle_types::mysql::types::MediumIntUnsigned,
1417    drizzle_types::mysql::types::IntUnsigned,
1418);
1419impl_mysql_sql_type_to_rust!(i64 => drizzle_types::mysql::types::BigInt);
1420impl_mysql_sql_type_to_rust!(u64 => drizzle_types::mysql::types::BigIntUnsigned);
1421impl_mysql_sql_type_to_rust!(f32 => drizzle_types::mysql::types::Float);
1422impl_mysql_sql_type_to_rust!(f64 => drizzle_types::mysql::types::Double);
1423impl_mysql_sql_type_to_rust!(bool => drizzle_types::mysql::types::Boolean);
1424impl_mysql_sql_type_to_rust!(crate::prelude::String =>
1425    drizzle_types::mysql::types::Char,
1426    drizzle_types::mysql::types::Varchar,
1427    drizzle_types::mysql::types::TinyText,
1428    drizzle_types::mysql::types::Text,
1429    drizzle_types::mysql::types::MediumText,
1430    drizzle_types::mysql::types::LongText,
1431    drizzle_types::mysql::types::Enum,
1432    drizzle_types::mysql::types::Set,
1433    drizzle_types::mysql::types::Any,
1434);
1435impl_mysql_sql_type_to_rust!(crate::prelude::Vec<u8> =>
1436    drizzle_types::mysql::types::Binary,
1437    drizzle_types::mysql::types::Varbinary,
1438    drizzle_types::mysql::types::TinyBlob,
1439    drizzle_types::mysql::types::Blob,
1440    drizzle_types::mysql::types::MediumBlob,
1441    drizzle_types::mysql::types::LongBlob,
1442    drizzle_types::mysql::types::Bit,
1443);
1444impl_mysql_sql_type_to_rust!(u16 => drizzle_types::mysql::types::Year);
1445
1446#[cfg(feature = "rust-decimal")]
1447impl_mysql_sql_type_to_rust!(rust_decimal::Decimal => drizzle_types::mysql::types::Decimal);
1448#[cfg(not(feature = "rust-decimal"))]
1449impl_mysql_sql_type_to_rust!(crate::prelude::String => drizzle_types::mysql::types::Decimal);
1450
1451#[cfg(feature = "serde")]
1452impl_mysql_sql_type_to_rust!(serde_json::Value => drizzle_types::mysql::types::Json);
1453#[cfg(not(feature = "serde"))]
1454impl_mysql_sql_type_to_rust!(crate::prelude::String => drizzle_types::mysql::types::Json);
1455
1456#[cfg(feature = "chrono")]
1457impl_mysql_sql_type_to_rust!(chrono::NaiveDate => drizzle_types::mysql::types::Date);
1458#[cfg(all(not(feature = "chrono"), feature = "time"))]
1459impl_mysql_sql_type_to_rust!(time::Date => drizzle_types::mysql::types::Date);
1460#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1461impl_mysql_sql_type_to_rust!(jiff::civil::Date => drizzle_types::mysql::types::Date);
1462#[cfg(not(any(feature = "chrono", feature = "time", feature = "jiff")))]
1463impl_mysql_sql_type_to_rust!(crate::prelude::String => drizzle_types::mysql::types::Date);
1464
1465// Unlike SQL TIME in SQLite/PostgreSQL, MySQL TIME is a signed duration that
1466// can exceed 24 hours (up to 838:59:59). Clock-only chrono/time values cannot
1467// represent its full domain, so the canonical selected value remains text,
1468// matching Drizzle ORM's MySQL TIME mapping.
1469impl_mysql_sql_type_to_rust!(crate::prelude::String => drizzle_types::mysql::types::Time);
1470
1471#[cfg(feature = "chrono")]
1472impl_mysql_sql_type_to_rust!(chrono::NaiveDateTime => drizzle_types::mysql::types::DateTime);
1473// MySQL TIMESTAMP is session-time-zone aware. Wire adapters must establish a
1474// UTC session before executing typed queries, so the public value is an
1475// explicit UTC instant rather than an ambiguous naive datetime.
1476#[cfg(feature = "chrono")]
1477impl_mysql_sql_type_to_rust!(chrono::DateTime<chrono::Utc> => drizzle_types::mysql::types::Timestamp);
1478#[cfg(all(not(feature = "chrono"), feature = "time"))]
1479impl_mysql_sql_type_to_rust!(time::PrimitiveDateTime => drizzle_types::mysql::types::DateTime);
1480#[cfg(all(not(feature = "chrono"), feature = "time"))]
1481impl_mysql_sql_type_to_rust!(time::OffsetDateTime => drizzle_types::mysql::types::Timestamp);
1482#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1483impl_mysql_sql_type_to_rust!(jiff::civil::DateTime => drizzle_types::mysql::types::DateTime);
1484#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1485impl_mysql_sql_type_to_rust!(jiff::Timestamp => drizzle_types::mysql::types::Timestamp);
1486#[cfg(not(any(feature = "chrono", feature = "time", feature = "jiff")))]
1487impl_mysql_sql_type_to_rust!(crate::prelude::String =>
1488    drizzle_types::mysql::types::DateTime,
1489    drizzle_types::mysql::types::Timestamp,
1490);
1491
1492impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Int2 {
1493    type RustType = i16;
1494}
1495
1496impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Int4 {
1497    type RustType = i32;
1498}
1499
1500impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Int8 {
1501    type RustType = i64;
1502}
1503
1504impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Float4 {
1505    type RustType = f32;
1506}
1507
1508impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Float8 {
1509    type RustType = f64;
1510}
1511
1512impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Varchar {
1513    type RustType = crate::prelude::String;
1514}
1515
1516impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Text {
1517    type RustType = crate::prelude::String;
1518}
1519
1520impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Char {
1521    type RustType = crate::prelude::String;
1522}
1523
1524impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Bytea {
1525    type RustType = crate::prelude::Vec<u8>;
1526}
1527
1528impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Boolean {
1529    type RustType = bool;
1530}
1531
1532#[cfg(feature = "rust-decimal")]
1533impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Numeric {
1534    type RustType = rust_decimal::Decimal;
1535}
1536
1537#[cfg(not(feature = "rust-decimal"))]
1538impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Numeric {
1539    type RustType = crate::prelude::String;
1540}
1541
1542impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Any {
1543    type RustType = crate::prelude::String;
1544}
1545
1546#[cfg(feature = "chrono")]
1547impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamptz {
1548    type RustType = chrono::DateTime<chrono::Utc>;
1549}
1550
1551#[cfg(feature = "chrono")]
1552impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamp {
1553    type RustType = chrono::NaiveDateTime;
1554}
1555
1556#[cfg(feature = "chrono")]
1557impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Date {
1558    type RustType = chrono::NaiveDate;
1559}
1560
1561#[cfg(feature = "chrono")]
1562impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Time {
1563    type RustType = chrono::NaiveTime;
1564}
1565
1566#[cfg(feature = "chrono")]
1567impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timetz {
1568    type RustType = chrono::NaiveTime;
1569}
1570
1571#[cfg(all(not(feature = "chrono"), feature = "time"))]
1572impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamptz {
1573    type RustType = time::OffsetDateTime;
1574}
1575
1576#[cfg(all(not(feature = "chrono"), feature = "time"))]
1577impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamp {
1578    type RustType = time::PrimitiveDateTime;
1579}
1580
1581#[cfg(all(not(feature = "chrono"), feature = "time"))]
1582impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Date {
1583    type RustType = time::Date;
1584}
1585
1586#[cfg(all(not(feature = "chrono"), feature = "time"))]
1587impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Time {
1588    type RustType = time::Time;
1589}
1590
1591#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1592impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamptz {
1593    type RustType = jiff::Timestamp;
1594}
1595
1596#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1597impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamp {
1598    type RustType = jiff::civil::DateTime;
1599}
1600
1601#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1602impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Date {
1603    type RustType = jiff::civil::Date;
1604}
1605
1606#[cfg(all(not(any(feature = "chrono", feature = "time")), feature = "jiff"))]
1607impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Time {
1608    type RustType = jiff::civil::Time;
1609}
1610
1611#[cfg(feature = "uuid")]
1612impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Uuid {
1613    type RustType = uuid::Uuid;
1614}
1615
1616#[cfg(feature = "serde")]
1617impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Json {
1618    type RustType = serde_json::Value;
1619}
1620
1621#[cfg(feature = "serde")]
1622impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Jsonb {
1623    type RustType = serde_json::Value;
1624}
1625
1626// -- Feature-gated type marker mappings --
1627
1628#[cfg(feature = "chrono")]
1629impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Interval {
1630    type RustType = chrono::Duration;
1631}
1632
1633#[cfg(not(feature = "chrono"))]
1634impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Interval {
1635    type RustType = crate::prelude::String;
1636}
1637
1638#[cfg(feature = "cidr")]
1639impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Inet {
1640    type RustType = cidr::IpInet;
1641}
1642
1643#[cfg(not(feature = "cidr"))]
1644impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Inet {
1645    type RustType = crate::prelude::String;
1646}
1647
1648#[cfg(feature = "cidr")]
1649impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Cidr {
1650    type RustType = cidr::IpCidr;
1651}
1652
1653#[cfg(not(feature = "cidr"))]
1654impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Cidr {
1655    type RustType = crate::prelude::String;
1656}
1657
1658impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::MacAddr {
1659    type RustType = crate::prelude::String;
1660}
1661
1662impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::MacAddr8 {
1663    type RustType = crate::prelude::String;
1664}
1665
1666#[cfg(feature = "geo-types")]
1667impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Point {
1668    type RustType = geo_types::Point<f64>;
1669}
1670
1671#[cfg(not(feature = "geo-types"))]
1672impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Point {
1673    type RustType = crate::prelude::String;
1674}
1675
1676#[cfg(feature = "geo-types")]
1677impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::LineString {
1678    type RustType = geo_types::LineString<f64>;
1679}
1680
1681#[cfg(not(feature = "geo-types"))]
1682impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::LineString {
1683    type RustType = crate::prelude::String;
1684}
1685
1686#[cfg(feature = "geo-types")]
1687impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Rect {
1688    type RustType = geo_types::Rect<f64>;
1689}
1690
1691#[cfg(not(feature = "geo-types"))]
1692impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Rect {
1693    type RustType = crate::prelude::String;
1694}
1695
1696#[cfg(feature = "bit-vec")]
1697impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::BitString {
1698    type RustType = bit_vec::BitVec;
1699}
1700
1701#[cfg(not(feature = "bit-vec"))]
1702impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::BitString {
1703    type RustType = crate::prelude::String;
1704}
1705
1706impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Line {
1707    type RustType = crate::prelude::String;
1708}
1709
1710impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::LineSegment {
1711    type RustType = crate::prelude::String;
1712}
1713
1714impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Polygon {
1715    type RustType = crate::prelude::String;
1716}
1717
1718impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Circle {
1719    type RustType = crate::prelude::String;
1720}
1721
1722impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Enum {
1723    type RustType = crate::prelude::String;
1724}
1725
1726// =============================================================================
1727// WrapNullable — Option<T> wrapping based on nullability
1728// =============================================================================
1729
1730/// `T` for [`NonNull`](crate::expr::NonNull), `Option<T>` for
1731/// [`Null`](crate::expr::Null).
1732pub trait WrapNullable<T> {
1733    /// The wrapped type.
1734    type Output;
1735}
1736
1737impl<T> WrapNullable<T> for crate::expr::NonNull {
1738    type Output = T;
1739}
1740
1741impl<T> WrapNullable<T> for crate::expr::Null {
1742    type Output = Option<T>;
1743}
1744
1745// =============================================================================
1746// ExprValueType — "what Rust type does this expression produce?"
1747// =============================================================================
1748
1749/// The Rust type a selected column or typed expression decodes into.
1750///
1751/// Implemented for:
1752/// - columns (generated by the table macros);
1753/// - `SQLExpr<V, T, N, A, S>`: [`SQLTypeToRust`] of `T`, wrapped in `Option`
1754///   when `N` is [`Null`](crate::expr::Null);
1755/// - raw `SQL<'a, V>`: `()`, so the caller must name the row type
1756///   (`.all::<T>()`).
1757#[diagnostic::on_unimplemented(
1758    message = "cannot infer Rust type for expression `{Self}`",
1759    label = "use typed expressions or derive FromRow to specify the Rust type",
1760    note = "raw SQL and JSON expressions require explicit type annotation"
1761)]
1762pub trait ExprValueType {
1763    /// The decoded Rust type.
1764    type ValueType;
1765}
1766
1767impl<T: ExprValueType + ?Sized> ExprValueType for &T {
1768    type ValueType = T::ValueType;
1769}
1770
1771impl<V: crate::SQLParam, T, N, A, S> ExprValueType for crate::expr::SQLExpr<'_, V, T, N, A, S>
1772where
1773    T: crate::types::DataType + SQLTypeToRust<V::DialectMarker>,
1774    N: crate::expr::Nullability + WrapNullable<<T as SQLTypeToRust<V::DialectMarker>>::RustType>,
1775    A: crate::expr::AggregateKind,
1776{
1777    type ValueType = <N as WrapNullable<<T as SQLTypeToRust<V::DialectMarker>>::RustType>>::Output;
1778}
1779
1780/// Raw SQL has no known type (`()`); the caller must name the row type.
1781impl<V: crate::SQLParam> ExprValueType for crate::sql::SQL<'_, V> {
1782    type ValueType = ();
1783}
1784
1785// =============================================================================
1786// HasSelectModel — table → Select model (lifetime-free)
1787// =============================================================================
1788
1789/// The select model and column count of a table.
1790///
1791/// Generated by `#[SQLiteTable]`, `#[PostgresTable]` and `#[MySQLTable]`.
1792/// `SELECT *` from the table decodes into `SelectModel`.
1793#[diagnostic::on_unimplemented(
1794    message = "`{Self}` is not a drizzle table",
1795    label = "ensure this type was derived with #[SQLiteTable], #[PostgresTable], or #[MySQLTable]"
1796)]
1797pub trait HasSelectModel {
1798    /// The struct a `SELECT *` row decodes into.
1799    type SelectModel;
1800    /// Number of columns in the table.
1801    const COLUMN_COUNT: usize;
1802}
1803
1804impl<T: HasSelectModel + ?Sized> HasSelectModel for &T {
1805    type SelectModel = T::SelectModel;
1806
1807    const COLUMN_COUNT: usize = T::COLUMN_COUNT;
1808}
1809
1810// =============================================================================
1811// ResolveRow — Marker + Table → default row type R
1812// =============================================================================
1813
1814/// The row type a select marker produces when selecting from `Table`.
1815///
1816/// Computed at `.from(table)`: the table's select model for `SELECT *`, a
1817/// tuple of value types for explicit columns, `R` for `SelectAs<R>`, and
1818/// `()` for raw SQL.
1819#[diagnostic::on_unimplemented(
1820    message = "cannot resolve return type for this query",
1821    label = "the selected columns and table do not produce a known row type"
1822)]
1823pub trait ResolveRow<Table> {
1824    /// The inferred row type.
1825    type Row;
1826}
1827
1828impl<T: HasSelectModel> ResolveRow<T> for SelectStar {
1829    type Row = T::SelectModel;
1830}
1831
1832impl<T> ResolveRow<T> for SelectExpr {
1833    type Row = ();
1834}
1835
1836impl<R, T> ResolveRow<T> for SelectAs<R>
1837where
1838    R: SelectAsFrom<T>,
1839{
1840    type Row = R;
1841}
1842
1843impl<M, Scope, Used, T> ResolveRow<T> for Scoped<M, Scope, Used>
1844where
1845    M: ResolveRow<T>,
1846{
1847    type Row = M::Row;
1848}
1849
1850/// The `FromRow` struct `Self` may select from `Table`.
1851///
1852/// Checked by `.select(MyRow::Select).from(table)`. `#[from(Table)]` on a
1853/// `FromRow` struct implements this for that table only. A struct without
1854/// `#[from(...)]` accepts any table.
1855#[diagnostic::on_unimplemented(
1856    message = "row selector `{Self}` cannot be used with table `{Table}`",
1857    label = "the #[from(...)] table does not match .from(...)",
1858    note = "set #[from(TheTable)] to the same table passed to .from(...)"
1859)]
1860pub trait SelectAsFrom<Table> {}
1861
1862// -- SelectCols: column value types → row tuple --
1863
1864macro_rules! impl_resolve_row_cols {
1865    ($($T:ident),+; $($idx:tt),+) => {
1866        impl<__Table, $($T: ExprValueType),+> ResolveRow<__Table> for SelectCols<($($T,)+)> {
1867            type Row = ($(<$T as ExprValueType>::ValueType,)+);
1868        }
1869    };
1870}
1871
1872with_col_sizes_8!(impl_resolve_row_cols);
1873
1874#[cfg(any(
1875    feature = "col16",
1876    feature = "col32",
1877    feature = "col64",
1878    feature = "col128",
1879    feature = "col200"
1880))]
1881with_col_sizes_16!(impl_resolve_row_cols);
1882
1883#[cfg(any(
1884    feature = "col32",
1885    feature = "col64",
1886    feature = "col128",
1887    feature = "col200"
1888))]
1889with_col_sizes_32!(impl_resolve_row_cols);
1890
1891#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1892with_col_sizes_64!(impl_resolve_row_cols);
1893
1894#[cfg(any(feature = "col128", feature = "col200"))]
1895with_col_sizes_128!(impl_resolve_row_cols);
1896
1897#[cfg(feature = "col200")]
1898with_col_sizes_200!(impl_resolve_row_cols);
1899
1900macro_rules! selected_columns_cons {
1901    () => {
1902        crate::Nil
1903    };
1904    ($head:ident $(, $tail:ident)*) => {
1905        crate::Cons<<$head as ExprValueType>::ValueType, selected_columns_cons!($($tail),*)>
1906    };
1907}
1908
1909macro_rules! selected_expressions_cons {
1910    () => {
1911        crate::Nil
1912    };
1913    ($head:ident $(, $tail:ident)*) => {
1914        crate::Cons<$head, selected_expressions_cons!($($tail),*)>
1915    };
1916}
1917
1918macro_rules! impl_selected_column_list_tuple {
1919    ($($T:ident),+; $($idx:tt),+) => {
1920        impl<$($T: ExprValueType),+> SelectedColumnList for ($($T,)+) {
1921            type Columns = selected_columns_cons!($($T),+);
1922        }
1923    };
1924}
1925
1926macro_rules! impl_selected_expression_list_tuple {
1927    ($($T:ident),+; $($idx:tt),+) => {
1928        impl<$($T),+> SelectedExpressionList for ($($T,)+) {
1929            type Expressions = selected_expressions_cons!($($T),+);
1930        }
1931    };
1932}
1933
1934with_col_sizes_8!(impl_selected_column_list_tuple);
1935with_col_sizes_8!(impl_selected_expression_list_tuple);
1936
1937#[cfg(any(
1938    feature = "col16",
1939    feature = "col32",
1940    feature = "col64",
1941    feature = "col128",
1942    feature = "col200"
1943))]
1944with_col_sizes_16!(impl_selected_column_list_tuple);
1945#[cfg(any(
1946    feature = "col16",
1947    feature = "col32",
1948    feature = "col64",
1949    feature = "col128",
1950    feature = "col200"
1951))]
1952with_col_sizes_16!(impl_selected_expression_list_tuple);
1953
1954#[cfg(any(
1955    feature = "col32",
1956    feature = "col64",
1957    feature = "col128",
1958    feature = "col200"
1959))]
1960with_col_sizes_32!(impl_selected_column_list_tuple);
1961#[cfg(any(
1962    feature = "col32",
1963    feature = "col64",
1964    feature = "col128",
1965    feature = "col200"
1966))]
1967with_col_sizes_32!(impl_selected_expression_list_tuple);
1968
1969#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1970with_col_sizes_64!(impl_selected_column_list_tuple);
1971#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1972with_col_sizes_64!(impl_selected_expression_list_tuple);
1973
1974#[cfg(any(feature = "col128", feature = "col200"))]
1975with_col_sizes_128!(impl_selected_column_list_tuple);
1976#[cfg(any(feature = "col128", feature = "col200"))]
1977with_col_sizes_128!(impl_selected_expression_list_tuple);
1978
1979#[cfg(feature = "col200")]
1980with_col_sizes_200!(impl_selected_column_list_tuple);
1981#[cfg(feature = "col200")]
1982with_col_sizes_200!(impl_selected_expression_list_tuple);
1983
1984// =============================================================================
1985// JoinRow — how joins transform the row type
1986// =============================================================================
1987
1988use crate::scope::{FullJoin, InnerJoin, JoinRow, LeftJoin, RightJoin};
1989
1990// LATERAL joins grow `SELECT *` rows like their plain kind.
1991impl<R, T, Kind> JoinRow<R, T, crate::scope::Lateral<Kind>> for SelectStar
1992where
1993    SelectStar: JoinRow<R, T, Kind>,
1994{
1995    type Row = <SelectStar as JoinRow<R, T, Kind>>::Row;
1996}
1997
1998/// Selections that stay valid after a `LEFT JOIN LATERAL`.
1999///
2000/// `SELECT *` decodes the joined source as `Option<JoinedTable::SelectModel>`.
2001/// Explicit columns and `FromRow` selections are accepted only when they read
2002/// sources already in scope before the lateral join: a column of the lateral
2003/// source would have to become nullable on unmatched rows.
2004#[doc(hidden)]
2005pub trait LeftLateralSelection<Proof = ()>: left_lateral_private::Sealed {}
2006
2007mod left_lateral_private {
2008    pub trait Sealed {}
2009
2010    impl Sealed for super::SelectStar {}
2011    impl<Scope, Used> Sealed for super::Scoped<super::SelectStar, Scope, Used> {}
2012    impl<Columns, Scope, Used> Sealed for super::Scoped<super::SelectCols<Columns>, Scope, Used> {}
2013    impl<Row, Scope, Used> Sealed for super::Scoped<super::SelectAs<Row>, Scope, Used> {}
2014}
2015
2016impl LeftLateralSelection for SelectStar {}
2017impl<Scope, Used> LeftLateralSelection for Scoped<SelectStar, Scope, Used> {}
2018
2019impl<Columns, Scope, Used, Proof> LeftLateralSelection<Proof>
2020    for Scoped<SelectCols<Columns>, Scope, Used>
2021where
2022    Columns: SelectedExpressionList,
2023    Columns::Expressions: ProjectionIn<Scope, Proof>,
2024{
2025}
2026
2027impl<Row, Scope, Used, Proof> LeftLateralSelection<Proof> for Scoped<SelectAs<Row>, Scope, Used>
2028where
2029    Row: SelectTableFields,
2030    Row::TableFields: TableFieldsIn<Scope, Proof>,
2031{
2032}
2033
2034/// `SELECT *` + JOIN → `(CurrentRow, JoinedTable::SelectModel)`.
2035impl<R, T: HasSelectModel> JoinRow<R, T, InnerJoin> for SelectStar {
2036    type Row = (R, T::SelectModel);
2037}
2038
2039/// `SELECT *` + LEFT JOIN → `(CurrentRow, Option<JoinedTable::SelectModel>)`.
2040impl<R, T: HasSelectModel> JoinRow<R, T, LeftJoin> for SelectStar {
2041    type Row = (R, Option<T::SelectModel>);
2042}
2043
2044/// `SELECT *` + RIGHT JOIN → `(Option<CurrentRow>, JoinedTable::SelectModel)`.
2045impl<R, T: HasSelectModel> JoinRow<R, T, RightJoin> for SelectStar {
2046    type Row = (Option<R>, T::SelectModel);
2047}
2048
2049/// `SELECT *` + FULL JOIN → `(Option<CurrentRow>, Option<JoinedTable::SelectModel>)`.
2050impl<R, T: HasSelectModel> JoinRow<R, T, FullJoin> for SelectStar {
2051    type Row = (Option<R>, Option<T::SelectModel>);
2052}
2053
2054/// Explicit columns + JOIN → R unchanged.
2055impl<Cols, R, T, Kind> JoinRow<R, T, Kind> for SelectCols<Cols> {
2056    type Row = R;
2057}
2058
2059/// Raw/untyped + JOIN → R unchanged.
2060impl<R, T, Kind> JoinRow<R, T, Kind> for SelectExpr {
2061    type Row = R;
2062}
2063
2064/// Explicit model + JOIN → R unchanged.
2065impl<Row, R, T, Kind> JoinRow<R, T, Kind> for SelectAs<Row> {
2066    type Row = R;
2067}
2068
2069// =============================================================================
2070// IntoSelectTarget — select arguments → Marker type
2071// =============================================================================
2072
2073/// Something that can be passed to `.select(...)`; picks the select marker.
2074///
2075/// The marker decides how the row type is inferred:
2076/// - [`SelectStar`]: the table's select model;
2077/// - [`SelectCols<C>`]: a tuple of the columns' value types;
2078/// - [`SelectExpr`]: the caller names the row type;
2079/// - [`SelectAs<R>`]: the `FromRow` struct `R`.
2080///
2081/// Implemented for:
2082/// - `()` -> `SelectStar`
2083/// - `SQL<'a, V>` -> `SelectExpr`
2084/// - `SQLExpr<'a, V, T, N, A, S>` -> `SelectCols<(Self,)>`
2085/// - tuples `(A, B, ...)` -> `SelectCols<(A, B, ...)>`
2086/// - columns and tables (generated by the table macros)
2087/// - `FromRow` selectors (generated by the `FromRow` derives) -> `SelectAs<R>`
2088#[diagnostic::on_unimplemented(
2089    message = "`{Self}` cannot be used as a select target",
2090    label = "this type does not implement IntoSelectTarget",
2091    note = "implement IntoSelectTarget or use a column, table, or typed expression"
2092)]
2093pub trait IntoSelectTarget {
2094    /// The select marker.
2095    type Marker;
2096}
2097
2098impl<T: IntoSelectTarget + ?Sized> IntoSelectTarget for &T {
2099    type Marker = T::Marker;
2100}
2101
2102/// `select(())` → `SelectStar` — infer row type from the table.
2103impl IntoSelectTarget for () {
2104    type Marker = SelectStar;
2105}
2106
2107/// `select(sql!(...))` → `SelectExpr` — user must specify row type.
2108impl<V: crate::SQLParam> IntoSelectTarget for crate::sql::SQL<'_, V> {
2109    type Marker = SelectExpr;
2110}
2111
2112/// `select(typed_expr)` → `SelectCols<(Expr,)>` — single typed expression.
2113impl<V: crate::SQLParam, T, N, A, S> IntoSelectTarget for crate::expr::SQLExpr<'_, V, T, N, A, S>
2114where
2115    T: crate::types::DataType,
2116    N: crate::expr::Nullability,
2117    A: crate::expr::AggregateKind,
2118{
2119    type Marker = SelectCols<(Self,)>;
2120}
2121
2122/// Tuples of select targets → `SelectCols<(A, B, ...)>`.
2123macro_rules! impl_into_select_target_tuple {
2124    ($($T:ident),+; $($idx:tt),+) => {
2125        impl<$($T),+> IntoSelectTarget for ($($T,)+) {
2126            type Marker = SelectCols<($($T,)+)>;
2127        }
2128    };
2129}
2130
2131with_col_sizes_8!(impl_into_select_target_tuple);
2132
2133#[cfg(any(
2134    feature = "col16",
2135    feature = "col32",
2136    feature = "col64",
2137    feature = "col128",
2138    feature = "col200"
2139))]
2140with_col_sizes_16!(impl_into_select_target_tuple);
2141
2142#[cfg(any(
2143    feature = "col32",
2144    feature = "col64",
2145    feature = "col128",
2146    feature = "col200"
2147))]
2148with_col_sizes_32!(impl_into_select_target_tuple);
2149
2150#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
2151with_col_sizes_64!(impl_into_select_target_tuple);
2152
2153#[cfg(any(feature = "col128", feature = "col200"))]
2154with_col_sizes_128!(impl_into_select_target_tuple);
2155
2156#[cfg(feature = "col200")]
2157with_col_sizes_200!(impl_into_select_target_tuple);