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