Skip to main content

drizzle_core/row/
mod.rs

1//! Type-safe row inference for query builders.
2//!
3//! Provides type-level machinery to infer the Rust return type from a query's
4//! selected columns, table, and joins — so `.all()` and `.get()` return the
5//! correct type without turbofish annotations.
6//!
7//! # Architecture
8//!
9//! ```rust
10//! # let _ = r####"
11//! .select(cols)    → Marker  (SelectStar | SelectCols<C> | SelectExpr)
12//! .from(table)     → R       (Marker + Table → row type via ResolveRow)
13//! .join(t2)        → R'      (Marker + R + JoinedTable → new R via AfterJoin)
14//! .all()           → Vec<R>  (R: FromDrizzleRow)
15//! # "####;
16//! ```
17
18// Driver-specific leaf FromDrizzleRow implementations
19#[cfg(feature = "libsql")]
20mod libsql;
21#[cfg(any(feature = "tokio-postgres", feature = "postgres-sync"))]
22mod postgres;
23#[cfg(feature = "rusqlite")]
24mod rusqlite;
25// Shared blanket impls for SQLite-flavored drivers whose cells are tagged
26// unions (rusqlite, libsql, turso). The driver-specific files above just
27// impl `SqliteValueRow` for their row type; everything else lives here.
28#[cfg(any(feature = "rusqlite", feature = "libsql", feature = "turso"))]
29pub(crate) mod sqlite_value;
30#[cfg(feature = "turso")]
31mod turso;
32
33use core::marker::PhantomData;
34
35use crate::error::DrizzleError;
36use crate::{Cons, Nil};
37
38// =============================================================================
39// Select Target Markers
40// =============================================================================
41
42/// Marker: `SELECT *` — R inferred from the table, grows with joins.
43#[derive(Debug, Clone, Copy, Default)]
44pub struct SelectStar;
45
46/// Marker: explicit columns — R inferred from column value types, stable across joins.
47#[derive(Debug, Clone, Copy, Default)]
48pub struct SelectCols<Cols>(PhantomData<Cols>);
49
50/// Marker: raw SQL or untyped expression — R must be user-specified.
51#[derive(Debug, Clone, Copy, Default)]
52pub struct SelectExpr;
53
54/// Marker: explicit row model target chosen by user.
55#[derive(Debug, Clone, Copy, Default)]
56pub struct SelectAs<R>(PhantomData<R>);
57
58/// Marker wrapper that carries in-scope tables.
59#[derive(Debug, Clone, Copy, Default)]
60pub struct Scoped<Marker, Scope>(PhantomData<(Marker, Scope)>);
61
62/// Declares the set of tables a custom row model requires.
63pub trait SelectRequiredTables {
64    type RequiredTables;
65}
66
67/// Type-level witness that a table exists at the head of a scope list.
68#[derive(Debug, Clone, Copy, Default)]
69pub struct ScopeHere;
70
71/// Type-level witness that a table exists deeper in a scope list.
72#[derive(Debug, Clone, Copy, Default)]
73pub struct ScopeThere<Prev>(PhantomData<Prev>);
74
75/// Type-level table membership in a scope list.
76pub trait ScopeContains<Table, Witness> {}
77
78impl<Head, Tail> ScopeContains<Head, ScopeHere> for Cons<Head, Tail> {}
79
80impl<Head, Tail, Table, Witness> ScopeContains<Table, ScopeThere<Witness>> for Cons<Head, Tail> where
81    Tail: ScopeContains<Table, Witness>
82{
83}
84
85/// Required-table list satisfaction.
86pub trait ScopeSatisfies<Required, Proof> {}
87
88impl<Scope> ScopeSatisfies<Nil, ()> for Scope {}
89
90impl<Scope, Head, Tail, HeadProof, TailProof>
91    ScopeSatisfies<Cons<Head, Tail>, (HeadProof, TailProof)> for Scope
92where
93    Scope: ScopeContains<Head, HeadProof> + ScopeSatisfies<Tail, TailProof>,
94{
95}
96
97/// Marker-level required-table extraction.
98pub trait MarkerRequiredTables {
99    type RequiredTables;
100}
101
102impl MarkerRequiredTables for SelectStar {
103    type RequiredTables = Nil;
104}
105
106impl<Cols> MarkerRequiredTables for SelectCols<Cols> {
107    type RequiredTables = Nil;
108}
109
110impl MarkerRequiredTables for SelectExpr {
111    type RequiredTables = Nil;
112}
113
114impl<R> MarkerRequiredTables for SelectAs<R>
115where
116    R: SelectRequiredTables,
117{
118    type RequiredTables = R::RequiredTables;
119}
120
121/// Marker validation for a specific scope-satisfaction proof.
122#[diagnostic::on_unimplemented(
123    message = "selected row requires tables not present in the current query scope",
124    label = "add .join(...) entries for every table referenced by this selector",
125    note = "for aliased selectors, use the same alias type in #[from(...)] and .from(...)"
126)]
127///
128/// ```
129/// use drizzle_core::{Cons, Nil, Scoped, SelectAs, SelectRequiredTables};
130/// use drizzle_core::row::{MarkerScopeValidFor, ScopeHere};
131///
132/// struct Users;
133/// struct Model;
134///
135/// impl SelectRequiredTables for Model {
136///     type RequiredTables = Cons<Users, Nil>;
137/// }
138///
139/// type Good = Scoped<SelectAs<Model>, Cons<Users, Nil>>;
140///
141/// fn needs_valid<M: MarkerScopeValidFor<(ScopeHere, ())>>() {}
142///
143/// fn main() {
144///     needs_valid::<Good>();
145/// }
146/// ```
147///
148/// ```compile_fail
149/// use drizzle_core::{Cons, Nil, Scoped, SelectAs, SelectRequiredTables};
150/// use drizzle_core::row::{MarkerScopeValidFor, ScopeHere};
151///
152/// struct Users;
153/// struct Posts;
154/// struct Model;
155///
156/// impl SelectRequiredTables for Model {
157///     type RequiredTables = Cons<Users, Nil>;
158/// }
159///
160/// type Bad = Scoped<SelectAs<Model>, Cons<Posts, Nil>>;
161///
162/// fn needs_valid<M: MarkerScopeValidFor<(ScopeHere, ())>>() {}
163///
164/// fn main() {
165///     needs_valid::<Bad>();
166/// }
167/// ```
168pub trait MarkerScopeValidFor<Proof> {}
169
170impl<M, Scope, Proof> MarkerScopeValidFor<Proof> for Scoped<M, Scope>
171where
172    M: MarkerRequiredTables,
173    Scope: ScopeSatisfies<<M as MarkerRequiredTables>::RequiredTables, Proof>,
174{
175}
176
177// =============================================================================
178// Aggregate status validation for SELECT lists
179// =============================================================================
180
181/// Fold the aggregate statuses of a tuple of expressions.
182///
183/// For a 1-tuple, returns the single element's status.
184/// For N-tuples, folds pairwise using `CombineAggStatus`.
185pub trait AggStatus {
186    type Status;
187}
188
189// 1-tuple base case
190impl<E: crate::expr::HasAggStatus> AggStatus for (E,) {
191    type Status = E::Status;
192}
193
194// Generate AggStatus for 2..N tuples.
195// The `with_col_sizes_*` macros call this incrementally as:
196//   callback!(T0; 0)  callback!(T0, T1; 0, 1)  callback!(T0, T1, T2; 0, 1, 2)  ...
197// We skip the 1-tuple (handled above) and implement 2+ tuples.
198macro_rules! impl_tuple_agg_status {
199    // 1-tuple: skip (already implemented above)
200    ($E0:ident; $i0:tt) => {};
201    // 2-tuple
202    ($E0:ident, $E1:ident; $i0:tt, $i1:tt) => {
203        impl<$E0, $E1> AggStatus for ($E0, $E1)
204        where
205            $E0: crate::expr::HasAggStatus,
206            $E1: crate::expr::HasAggStatus,
207            <$E0 as crate::expr::HasAggStatus>::Status:
208                crate::expr::CombineAggStatus<<$E1 as crate::expr::HasAggStatus>::Status>,
209        {
210            type Status = <<$E0 as crate::expr::HasAggStatus>::Status as
211                crate::expr::CombineAggStatus<<$E1 as crate::expr::HasAggStatus>::Status>>::Output;
212        }
213    };
214    // 3+ tuples: fold head element's status with the rest-tuple's status
215    ($E0:ident, $E1:ident, $($rest:ident),+; $i0:tt, $i1:tt, $($ri:tt),+) => {
216        impl<$E0, $E1, $($rest),+> AggStatus for ($E0, $E1, $($rest),+)
217        where
218            $E0: crate::expr::HasAggStatus,
219            ($E1, $($rest),+): AggStatus,
220            <$E0 as crate::expr::HasAggStatus>::Status:
221                crate::expr::CombineAggStatus<<($E1, $($rest),+) as AggStatus>::Status>,
222        {
223            type Status = <<$E0 as crate::expr::HasAggStatus>::Status as
224                crate::expr::CombineAggStatus<<($E1, $($rest),+) as AggStatus>::Status>>::Output;
225        }
226    };
227}
228
229with_col_sizes_8!(impl_tuple_agg_status);
230
231#[cfg(any(
232    feature = "col16",
233    feature = "col32",
234    feature = "col64",
235    feature = "col128",
236    feature = "col200"
237))]
238with_col_sizes_16!(impl_tuple_agg_status);
239
240#[cfg(any(
241    feature = "col32",
242    feature = "col64",
243    feature = "col128",
244    feature = "col200"
245))]
246with_col_sizes_32!(impl_tuple_agg_status);
247
248#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
249with_col_sizes_64!(impl_tuple_agg_status);
250
251#[cfg(any(feature = "col128", feature = "col200"))]
252with_col_sizes_128!(impl_tuple_agg_status);
253
254#[cfg(feature = "col200")]
255with_col_sizes_200!(impl_tuple_agg_status);
256
257// =============================================================================
258// GROUP BY column tracking
259// =============================================================================
260
261/// Trait for types that can be passed to `.group_by()`.
262///
263/// Single columns and tuples of columns implement this.
264/// The `Columns` associated type is a `Cons<...>` list of column types
265/// for compile-time validation.
266pub trait IntoGroupBy<'a, V: crate::SQLParam + 'a>: crate::ToSQL<'a, V> {
267    /// Type-level list of grouped columns (e.g., `Cons<Col1, Cons<Col2, Nil>>`).
268    type Columns;
269}
270
271// Single column → Cons<Self, Nil>
272// (Implemented by proc macros for each column ZST)
273
274/// Type-level GROUP BY marker: the group key is table `Table`'s single-column
275/// primary key.
276///
277/// Produced by the proc-macro `IntoGroupBy` impl when `.group_by(col)` is
278/// called with a table's sole primary-key column. Every other column of that
279/// table is functionally dependent on its primary key (SQL:1999), so any
280/// scalar column of `Table` may appear in SELECT without being listed in
281/// GROUP BY. Columns of *other* tables (e.g. joined tables) still must be
282/// aggregated.
283///
284/// Beyond correctness, grouping by the bare primary key lets the database
285/// stream groups off the PK order instead of sorting the full result through
286/// a temp structure, which matters for `GROUP BY ... ORDER BY pk LIMIT n`.
287#[derive(Debug, Clone, Copy, Default)]
288pub struct PkGroup<Table>(PhantomData<Table>);
289
290// Tuple impls: (Col1, Col2) → Cons<Col1, Cons<Col2, Nil>>
291macro_rules! impl_into_group_by_tuple {
292    // 1-tuple: skip (single column uses direct impl)
293    ($T0:ident; $i0:tt) => {};
294    // 2-tuple
295    ($T0:ident, $T1:ident; $i0:tt, $i1:tt) => {
296        impl<'a, V: crate::SQLParam + 'a, $T0, $T1> IntoGroupBy<'a, V> for ($T0, $T1)
297        where
298            $T0: crate::ToSQL<'a, V>,
299            $T1: crate::ToSQL<'a, V>,
300        {
301            type Columns = Cons<$T0, Cons<$T1, Nil>>;
302        }
303    };
304    // 3+ tuples
305    ($T0:ident, $T1:ident, $($rest:ident),+; $i0:tt, $i1:tt, $($ri:tt),+) => {
306        impl<'a, V: crate::SQLParam + 'a, $T0, $T1, $($rest),+> IntoGroupBy<'a, V> for ($T0, $T1, $($rest),+)
307        where
308            $T0: crate::ToSQL<'a, V>,
309            $T1: crate::ToSQL<'a, V>,
310            $($rest: crate::ToSQL<'a, V>,)+
311        {
312            type Columns = impl_into_group_by_tuple!(@cons $T0, $T1, $($rest),+);
313        }
314    };
315    // Helper: build nested Cons type
316    (@cons $T:ident) => { Cons<$T, Nil> };
317    (@cons $T:ident, $($rest:ident),+) => { Cons<$T, impl_into_group_by_tuple!(@cons $($rest),+)> };
318}
319
320with_col_sizes_8!(impl_into_group_by_tuple);
321
322#[cfg(any(
323    feature = "col16",
324    feature = "col32",
325    feature = "col64",
326    feature = "col128",
327    feature = "col200"
328))]
329with_col_sizes_16!(impl_into_group_by_tuple);
330
331// =============================================================================
332// Scalar column validation against grouped columns
333// =============================================================================
334
335/// Checks that every scalar column in a `SelectCols` tuple is present in
336/// the Grouped column list. Aggregate columns are skipped.
337///
338/// `Proof` is a witness type inferred by the compiler (like `ScopeContains`).
339#[diagnostic::on_unimplemented(
340    message = "non-aggregate column in SELECT is not in GROUP BY",
341    label = "this column must appear in .group_by(...) or be wrapped in an aggregate function",
342    note = "when using GROUP BY, every non-aggregate column in SELECT must be listed in GROUP BY, \
343            unless the group key is the column's table primary key (`.group_by(table.pk)`)"
344)]
345pub trait ScalarColumnsIn<Grouped, Proof> {}
346
347/// Aggregate expressions always pass (they don't need to be in GROUP BY).
348pub struct AggSkip;
349
350/// Scalar expressions need a `ScopeContains` witness.
351pub struct ScalarCheck<W>(core::marker::PhantomData<W>);
352
353/// Witness: scalar column allowed because the group key is its table's
354/// primary key (functional dependency).
355pub struct PkDependent;
356
357// 1-tuple
358impl<E, Grouped, Proof> ScalarColumnsIn<Grouped, (Proof,)> for (E,) where
359    E: SingleColGroupCheck<Grouped, Proof>
360{
361}
362
363/// Per-element check: either skip (Agg) or verify (Scalar).
364pub trait SingleColGroupCheck<Grouped, Proof> {}
365
366/// Extracts the "base column" identity from an expression for GROUP BY matching.
367///
368/// `AliasedExpr<Col>` → `Col`, bare column → `Self`.
369pub trait GroupByIdentity {
370    type Identity;
371}
372
373// Default: identity is self (bare column ZSTs)
374// (implemented by proc macros for each column ZST)
375
376// AliasedExpr unwraps to inner
377impl<E: GroupByIdentity> GroupByIdentity for crate::expr::AliasedExpr<E> {
378    type Identity = E::Identity;
379}
380
381// SQLExpr: identity is self (for aggregate expressions, this won't be checked anyway)
382impl<V: crate::SQLParam, T, N, A> GroupByIdentity for crate::expr::SQLExpr<'_, V, T, N, A>
383where
384    T: crate::types::DataType,
385    N: crate::expr::Nullability,
386    A: crate::expr::AggregateKind,
387{
388    type Identity = Self;
389}
390
391// ColumnBinOp: identity is self (complex expressions won't match GROUP BY)
392impl<Lhs, Rhs, Op> GroupByIdentity for crate::expr::ColumnBinOp<Lhs, Rhs, Op> {
393    type Identity = Self;
394}
395
396// ColumnNeg: identity is self
397impl<T> GroupByIdentity for crate::expr::ColumnNeg<T> {
398    type Identity = Self;
399}
400
401// Aggregate expressions → always OK
402impl<E, Grouped> SingleColGroupCheck<Grouped, AggSkip> for E where
403    E: crate::expr::HasAggStatus<Status = crate::expr::AllAgg>
404{
405}
406
407// Scalar expressions → base column identity must be in Grouped list
408impl<E, Grouped, W> SingleColGroupCheck<Grouped, ScalarCheck<W>> for E
409where
410    E: crate::expr::HasAggStatus<Status = crate::expr::AllScalar> + GroupByIdentity,
411    Grouped: ScopeContains<E::Identity, W>,
412{
413}
414
415// Scalar expressions under a primary-key group → the whole row of that table
416// is functionally dependent on the group key, so any column of the grouped
417// table passes. No overlap with the `ScalarCheck` impl above: `PkGroup<T>`
418// never implements `ScopeContains`.
419impl<E, T> SingleColGroupCheck<PkGroup<T>, PkDependent> for E
420where
421    E: crate::expr::HasAggStatus<Status = crate::expr::AllScalar> + GroupByIdentity,
422    E::Identity: crate::traits::ColumnOf<T>,
423{
424}
425
426// N-tuple: check head element, recurse on tail
427// Uses (HeadProof, TailProof) witness structure, like ScopeSatisfies.
428
429// 2-tuple
430impl<T0, T1, Grouped, P0, P1> ScalarColumnsIn<Grouped, (P0, P1)> for (T0, T1)
431where
432    T0: SingleColGroupCheck<Grouped, P0>,
433    T1: SingleColGroupCheck<Grouped, P1>,
434{
435}
436
437// 3+ tuples: check head, recurse on (T1, T2, ...)
438macro_rules! impl_scalar_columns_in {
439    // 1-tuple: skip (handled above directly)
440    ($T0:ident; $i0:tt) => {};
441    // 2-tuple: skip (handled above directly)
442    ($T0:ident, $T1:ident; $i0:tt, $i1:tt) => {};
443    // 3+ tuples: head + tail recursion
444    ($T0:ident, $($rest:ident),+; $i0:tt, $($ri:tt),+) => {
445        impl<$T0, $($rest),+, Grouped, HeadProof, TailProof>
446            ScalarColumnsIn<Grouped, (HeadProof, TailProof)>
447            for ($T0, $($rest),+)
448        where
449            $T0: SingleColGroupCheck<Grouped, HeadProof>,
450            ($($rest,)+): ScalarColumnsIn<Grouped, TailProof>,
451        {}
452    };
453}
454
455with_col_sizes_8!(impl_scalar_columns_in);
456
457#[cfg(any(
458    feature = "col16",
459    feature = "col32",
460    feature = "col64",
461    feature = "col128",
462    feature = "col200"
463))]
464with_col_sizes_16!(impl_scalar_columns_in);
465
466// =============================================================================
467// MarkerAggValidFor — top-level bound on terminal methods
468// =============================================================================
469
470/// Validates that the SELECT list is legal given the grouped column set.
471///
472/// - `Grouped = ()` (no GROUP BY): everything is valid
473/// - `Grouped = Cons<...>` (has GROUP BY): scalar columns must be in the list
474#[diagnostic::on_unimplemented(
475    message = "non-aggregate column in SELECT is not in GROUP BY",
476    label = "add this column to .group_by(...) or wrap it in an aggregate function"
477)]
478pub trait MarkerAggValidFor<Grouped, Proof = ()> {}
479
480// No GROUP BY (Grouped = ()) → always valid, any mix is fine
481impl<Mk> MarkerAggValidFor<()> for Mk {}
482
483// SelectStar with GROUP BY: can't check at compile time, always passes
484impl<Scope, Head, Tail> MarkerAggValidFor<Cons<Head, Tail>> for Scoped<SelectStar, Scope> {}
485
486// SelectExpr with GROUP BY: can't check, always passes
487impl<Scope, Head, Tail> MarkerAggValidFor<Cons<Head, Tail>> for Scoped<SelectExpr, Scope> {}
488
489// SelectAs with GROUP BY: user-specified type, always passes
490impl<Scope, R, Head, Tail> MarkerAggValidFor<Cons<Head, Tail>> for Scoped<SelectAs<R>, Scope> {}
491
492// SelectCols with GROUP BY: check each scalar column is in the Grouped list
493impl<Scope, Cols, Head, Tail, Proof> MarkerAggValidFor<Cons<Head, Tail>, Proof>
494    for Scoped<SelectCols<Cols>, Scope>
495where
496    Cols: ScalarColumnsIn<Cons<Head, Tail>, Proof>,
497{
498}
499
500// GROUP BY a table's primary key (`Grouped = PkGroup<T>`): same shape as the
501// Cons impls above, but scalar columns are checked for membership in the
502// grouped table instead of the grouped column list.
503impl<Scope, T> MarkerAggValidFor<PkGroup<T>> for Scoped<SelectStar, Scope> {}
504
505impl<Scope, T> MarkerAggValidFor<PkGroup<T>> for Scoped<SelectExpr, Scope> {}
506
507impl<Scope, R, T> MarkerAggValidFor<PkGroup<T>> for Scoped<SelectAs<R>, Scope> {}
508
509impl<Scope, Cols, T, Proof> MarkerAggValidFor<PkGroup<T>, Proof> for Scoped<SelectCols<Cols>, Scope> where
510    Cols: ScalarColumnsIn<PkGroup<T>, Proof>
511{
512}
513
514// =============================================================================
515// Marker column-count validation for strict decode paths
516// =============================================================================
517
518/// Type-level column-list representation for a row decode target.
519///
520/// Each consumed column is represented by a `Cons<T, ...>` node where `T`
521/// is the decoded Rust type for that column.
522pub trait RowColumnList<Row: ?Sized> {
523    type Columns: crate::TypeSet;
524}
525
526/// Type-level column-list representation for selected column tuples.
527pub trait SelectedColumnList {
528    type Columns: crate::TypeSet;
529}
530
531trait SameType<T> {}
532impl<T> SameType<T> for T {}
533
534trait ColumnTypeCompatible<Row: ?Sized, Expected, Actual> {}
535
536impl<Row: ?Sized, T> ColumnTypeCompatible<Row, T, T> for () {}
537
538trait TypeListCompatible<Row: ?Sized, ActualList> {}
539
540impl<Row: ?Sized> TypeListCompatible<Row, Self> for crate::Nil {}
541
542impl<Row: ?Sized, EH, ET, AH, AT> TypeListCompatible<Row, crate::Cons<AH, AT>>
543    for crate::Cons<EH, ET>
544where
545    (): ColumnTypeCompatible<Row, EH, AH>,
546    ET: TypeListCompatible<Row, AT>,
547{
548}
549
550trait SqliteDecodeRow {}
551
552#[cfg(feature = "rusqlite")]
553impl SqliteDecodeRow for ::rusqlite::Row<'_> {}
554
555#[cfg(feature = "libsql")]
556impl SqliteDecodeRow for ::libsql::Row {}
557
558#[cfg(feature = "turso")]
559impl SqliteDecodeRow for ::turso::Row {}
560
561macro_rules! impl_sqlite_integer_decode_compat {
562    ($expected:ty => $($actual:ty),+ $(,)?) => {
563        $(
564            impl<Row> ColumnTypeCompatible<Row, $expected, $actual> for ()
565            where
566                Row: SqliteDecodeRow,
567            {
568            }
569        )+
570    };
571}
572
573impl_sqlite_integer_decode_compat!(
574    i64 => i8, i16, i32, isize, u8, u16, u32, u64, usize, bool
575);
576
577impl_sqlite_integer_decode_compat!(
578    Option<i64> =>
579        Option<i8>,
580        Option<i16>,
581        Option<i32>,
582        Option<isize>,
583        Option<u8>,
584        Option<u16>,
585        Option<u32>,
586        Option<u64>,
587        Option<usize>,
588        Option<bool>
589);
590
591macro_rules! impl_row_column_list_one {
592    ($($ty:ty),+ $(,)?) => {
593        $(
594            impl<Row: ?Sized> RowColumnList<Row> for $ty {
595                type Columns = crate::Cons<$ty, crate::Nil>;
596            }
597        )+
598    };
599}
600
601impl_row_column_list_one!(
602    i8,
603    i16,
604    i32,
605    i64,
606    isize,
607    u8,
608    u16,
609    u32,
610    u64,
611    usize,
612    f32,
613    f64,
614    bool,
615    crate::prelude::String,
616    crate::prelude::Vec<u8>
617);
618
619impl<Row: ?Sized> RowColumnList<Row> for () {
620    type Columns = crate::Cons<(), crate::Nil>;
621}
622
623#[cfg(feature = "uuid")]
624impl<Row: ?Sized> RowColumnList<Row> for uuid::Uuid {
625    type Columns = crate::Cons<Self, crate::Nil>;
626}
627
628#[cfg(feature = "chrono")]
629impl<Row: ?Sized> RowColumnList<Row> for chrono::NaiveDate {
630    type Columns = crate::Cons<Self, crate::Nil>;
631}
632
633#[cfg(feature = "chrono")]
634impl<Row: ?Sized> RowColumnList<Row> for chrono::NaiveTime {
635    type Columns = crate::Cons<Self, crate::Nil>;
636}
637
638#[cfg(feature = "chrono")]
639impl<Row: ?Sized> RowColumnList<Row> for chrono::NaiveDateTime {
640    type Columns = crate::Cons<Self, crate::Nil>;
641}
642
643#[cfg(feature = "chrono")]
644impl<Row: ?Sized> RowColumnList<Row> for chrono::DateTime<chrono::Utc> {
645    type Columns = crate::Cons<Self, crate::Nil>;
646}
647
648#[cfg(feature = "serde")]
649impl<Row: ?Sized> RowColumnList<Row> for serde_json::Value {
650    type Columns = crate::Cons<Self, crate::Nil>;
651}
652
653#[cfg(feature = "rust-decimal")]
654impl<Row: ?Sized> RowColumnList<Row> for rust_decimal::Decimal {
655    type Columns = crate::Cons<Self, crate::Nil>;
656}
657
658#[cfg(feature = "chrono")]
659impl<Row: ?Sized> RowColumnList<Row> for chrono::Duration {
660    type Columns = crate::Cons<Self, crate::Nil>;
661}
662
663#[cfg(feature = "cidr")]
664impl<Row: ?Sized> RowColumnList<Row> for cidr::IpInet {
665    type Columns = crate::Cons<Self, crate::Nil>;
666}
667
668#[cfg(feature = "cidr")]
669impl<Row: ?Sized> RowColumnList<Row> for cidr::IpCidr {
670    type Columns = crate::Cons<Self, crate::Nil>;
671}
672
673#[cfg(feature = "geo-types")]
674impl<Row: ?Sized> RowColumnList<Row> for geo_types::Point<f64> {
675    type Columns = crate::Cons<Self, crate::Nil>;
676}
677
678#[cfg(feature = "geo-types")]
679impl<Row: ?Sized> RowColumnList<Row> for geo_types::LineString<f64> {
680    type Columns = crate::Cons<Self, crate::Nil>;
681}
682
683#[cfg(feature = "geo-types")]
684impl<Row: ?Sized> RowColumnList<Row> for geo_types::Rect<f64> {
685    type Columns = crate::Cons<Self, crate::Nil>;
686}
687
688#[cfg(feature = "bit-vec")]
689impl<Row: ?Sized> RowColumnList<Row> for bit_vec::BitVec {
690    type Columns = crate::Cons<Self, crate::Nil>;
691}
692
693#[cfg(feature = "arrayvec")]
694impl<Row: ?Sized, const N: usize> RowColumnList<Row> for arrayvec::ArrayString<N> {
695    type Columns = crate::Cons<Self, crate::Nil>;
696}
697
698#[cfg(feature = "arrayvec")]
699impl<Row: ?Sized, T, const N: usize> RowColumnList<Row> for arrayvec::ArrayVec<T, N> {
700    type Columns = crate::Cons<Self, crate::Nil>;
701}
702
703impl<Row: ?Sized> RowColumnList<Row> for compact_str::CompactString {
704    type Columns = crate::Cons<Self, crate::Nil>;
705}
706
707#[cfg(feature = "bytes")]
708impl<Row: ?Sized> RowColumnList<Row> for bytes::Bytes {
709    type Columns = crate::Cons<Self, crate::Nil>;
710}
711
712#[cfg(feature = "bytes")]
713impl<Row: ?Sized> RowColumnList<Row> for bytes::BytesMut {
714    type Columns = crate::Cons<Self, crate::Nil>;
715}
716
717impl<Row: ?Sized, A: smallvec::Array> RowColumnList<Row> for smallvec::SmallVec<A> {
718    type Columns = crate::Cons<Self, crate::Nil>;
719}
720
721impl<Row: ?Sized, T> RowColumnList<Row> for Option<T> {
722    type Columns = crate::Cons<Self, crate::Nil>;
723}
724
725/// Helper: split last element from a type list and generate `RowColumnList` impl.
726/// Called by `impl_rcl_tuple` after separating first from rest.
727macro_rules! impl_rcl_body {
728    // 1-tuple: just delegate
729    ([$A:ident] []) => {
730        impl<Row: ?Sized, $A: RowColumnList<Row>> RowColumnList<Row> for ($A,) {
731            type Columns = <$A as RowColumnList<Row>>::Columns;
732        }
733    };
734    // N-tuple: delegate to (N-1)-tuple, concat last
735    ([$($all:ident),+] [$($prev:ident),+; $last:ident]) => {
736        impl<Row: ?Sized, $($all),+> RowColumnList<Row> for ($($all,)+)
737        where
738            $last: RowColumnList<Row>,
739            ($($prev,)+): RowColumnList<Row>,
740            <($($prev,)+) as RowColumnList<Row>>::Columns:
741                crate::Concat<<$last as RowColumnList<Row>>::Columns>,
742        {
743            type Columns = <<($($prev,)+) as RowColumnList<Row>>::Columns as crate::Concat<
744                <$last as RowColumnList<Row>>::Columns,
745            >>::Output;
746        }
747    };
748}
749
750/// Callback for `with_type_sizes_*!`: receives all types, separates last via
751/// recursive accumulator, then delegates to `impl_rcl_body`.
752macro_rules! impl_rcl_tuple {
753    ($($T:ident),+) => {
754        impl_rcl_split!([$($T),+] [] $($T),+);
755    };
756}
757
758/// Recursive accumulator to split `[all] [prev...] remaining...`
759macro_rules! impl_rcl_split {
760    // 1-tuple: no prev, single element
761    ([$A:ident] [] $only:ident) => {
762        impl_rcl_body!([$A] []);
763    };
764    // Base: one element left in remaining = it's the last
765    ([$($all:ident),+] [$($prev:ident),+] $last:ident) => {
766        impl_rcl_body!([$($all),+] [$($prev),+; $last]);
767    };
768    // Recurse from empty prev
769    ([$($all:ident),+] [] $head:ident, $($rest:ident),+) => {
770        impl_rcl_split!([$($all),+] [$head] $($rest),+);
771    };
772    // Recurse with non-empty prev
773    ([$($all:ident),+] [$($prev:ident),+] $head:ident, $($rest:ident),+) => {
774        impl_rcl_split!([$($all),+] [$($prev),+, $head] $($rest),+);
775    };
776}
777
778with_type_sizes_8!(impl_rcl_tuple);
779
780#[cfg(any(
781    feature = "col16",
782    feature = "col32",
783    feature = "col64",
784    feature = "col128",
785    feature = "col200"
786))]
787with_type_sizes_16!(impl_rcl_tuple);
788
789#[cfg(any(
790    feature = "col32",
791    feature = "col64",
792    feature = "col128",
793    feature = "col200"
794))]
795with_type_sizes_32!(impl_rcl_tuple);
796
797/// Marker-level column-count compatibility check used by strict `.all()` / `.get()`.
798///
799/// Currently enforced for `SelectCols<_>` where selected shape is explicit.
800#[diagnostic::on_unimplemented(
801    message = "selected shape does not match decode target `{Actual}`",
802    label = "this decode target is not type-compatible with .select(...) output",
803    note = "use typed expressions or derive FromRow for explicit remapping when selecting custom expressions"
804)]
805pub trait MarkerColumnCountValid<Row: ?Sized, Inferred, Actual> {}
806
807/// Marker-level guard for strict decode entry points.
808///
809/// Raw `SelectExpr` (`select(sql!(...))`) is intentionally excluded so strict
810/// decode requires either typed expressions (`raw_non_null`, `sql!(.., Type)`) or
811/// explicit remapping via typed expressions or `FromRow` derive.
812#[diagnostic::on_unimplemented(
813    message = "raw select expressions require explicit typing in strict decode",
814    label = "`select(sql!(...)).all()/get()` is not allowed in strict mode",
815    note = "use typed wrappers like `raw_non_null`/`raw_nullable` or derive FromRow"
816)]
817pub trait StrictDecodeMarker {}
818
819impl StrictDecodeMarker for SelectStar {}
820impl<Cols> StrictDecodeMarker for SelectCols<Cols> {}
821impl<R> StrictDecodeMarker for SelectAs<R> {}
822impl<M, Scope> StrictDecodeMarker for Scoped<M, Scope> where M: StrictDecodeMarker {}
823
824impl<Row: ?Sized, Inferred, Actual> MarkerColumnCountValid<Row, Inferred, Actual> for SelectStar {}
825
826impl<Row: ?Sized, Cols, Inferred, Actual> MarkerColumnCountValid<Row, Inferred, Actual>
827    for SelectCols<Cols>
828where
829    Cols: SelectedColumnList,
830    Actual: RowColumnList<Row>,
831    <Cols as SelectedColumnList>::Columns:
832        TypeListCompatible<Row, <Actual as RowColumnList<Row>>::Columns>,
833{
834}
835
836impl<Row: ?Sized, Inferred, Actual> MarkerColumnCountValid<Row, Inferred, Actual> for SelectExpr where
837    Inferred: SameType<Actual>
838{
839}
840
841impl<Row: ?Sized, R, Inferred, Actual> MarkerColumnCountValid<Row, Inferred, Actual>
842    for SelectAs<R>
843{
844}
845
846impl<M, Scope, Row: ?Sized, Inferred, Actual> MarkerColumnCountValid<Row, Inferred, Actual>
847    for Scoped<M, Scope>
848where
849    M: MarkerColumnCountValid<Row, Inferred, Actual>,
850{
851}
852
853/// Pushes a joined table into the marker scope.
854pub trait ScopePush<Joined> {
855    type Out;
856}
857
858impl<M, Scope, Joined> ScopePush<Joined> for Scoped<M, Scope> {
859    type Out = Scoped<M, Cons<Joined, Scope>>;
860}
861
862/// Marker-directed row decoding for `.all()`/`.get()`.
863pub trait DecodeSelectedRef<RowRef, R> {
864    /// Decode the row into `R` according to the marker.
865    ///
866    /// # Errors
867    ///
868    /// Returns an error if the row cannot be decoded into the expected type
869    /// (missing columns, type mismatch, or downstream conversion failure).
870    fn decode(row: RowRef) -> Result<R, DrizzleError>;
871}
872
873impl<RowRef, R> DecodeSelectedRef<RowRef, R> for SelectAs<R>
874where
875    R: TryFrom<RowRef>,
876    <R as TryFrom<RowRef>>::Error: Into<DrizzleError>,
877{
878    fn decode(row: RowRef) -> Result<R, DrizzleError> {
879        R::try_from(row).map_err(Into::into)
880    }
881}
882
883impl<RowRef, R, M, Scope> DecodeSelectedRef<RowRef, R> for Scoped<M, Scope>
884where
885    M: DecodeSelectedRef<RowRef, R>,
886{
887    fn decode(row: RowRef) -> Result<R, DrizzleError> {
888        M::decode(row)
889    }
890}
891
892impl<RowRef, Row: ?Sized, R> DecodeSelectedRef<RowRef, R> for SelectStar
893where
894    RowRef: core::ops::Deref<Target = Row>,
895    R: FromDrizzleRow<Row>,
896{
897    fn decode(row: RowRef) -> Result<R, DrizzleError> {
898        R::from_row(&*row)
899    }
900}
901
902impl<RowRef, Row: ?Sized, Cols, R> DecodeSelectedRef<RowRef, R> for SelectCols<Cols>
903where
904    RowRef: core::ops::Deref<Target = Row>,
905    R: FromDrizzleRow<Row>,
906{
907    fn decode(row: RowRef) -> Result<R, DrizzleError> {
908        R::from_row(&*row)
909    }
910}
911
912impl<RowRef, Row: ?Sized, R> DecodeSelectedRef<RowRef, R> for SelectExpr
913where
914    RowRef: core::ops::Deref<Target = Row>,
915    R: FromDrizzleRow<Row>,
916{
917    fn decode(row: RowRef) -> Result<R, DrizzleError> {
918        R::from_row(&*row)
919    }
920}
921
922// =============================================================================
923// FromDrizzleRow — offset-based row extraction
924// =============================================================================
925
926/// Extracts a Rust value from a database row at a given column offset.
927///
928/// Unlike `TryFrom<Row>`, supports offset-based reading so joined results
929/// can split a single row across multiple model types.
930///
931/// Tuple impls compose: `(A, B)` reads A at `offset`, then B at
932/// `offset + A::COLUMN_COUNT`.
933#[diagnostic::on_unimplemented(
934    message = "cannot deserialize `{Self}` from a database row",
935    label = "this type does not implement FromDrizzleRow",
936    note = "derive #[SQLiteFromRow] or #[PostgresFromRow]"
937)]
938pub trait FromDrizzleRow<Row: ?Sized>: Sized {
939    /// Number of columns this type reads from the row.
940    const COLUMN_COUNT: usize;
941
942    /// Read this type from `row` starting at column `offset`.
943    ///
944    /// # Errors
945    ///
946    /// Returns an error if any column from `offset` through
947    /// `offset + COLUMN_COUNT - 1` cannot be read or converted.
948    fn from_row_at(row: &Row, offset: usize) -> Result<Self, DrizzleError>;
949
950    /// Read from offset 0.
951    ///
952    /// # Errors
953    ///
954    /// Returns an error if the row cannot be decoded — see [`Self::from_row_at`].
955    fn from_row(row: &Row) -> Result<Self, DrizzleError> {
956        Self::from_row_at(row, 0)
957    }
958}
959
960/// Trait for composite (multi-column) row types that support NULL probing.
961///
962/// Implementing this trait enables `Option<T>` to work as a `FromDrizzleRow`
963/// target, used for LEFT JOIN results where the joined table may be absent
964/// (all columns NULL).
965///
966/// Proc macros generate this for each `SelectModel`. Leaf types (i32, String,
967/// etc.) use concrete `Option<T>` impls instead.
968pub trait NullProbeRow<Row: ?Sized>: FromDrizzleRow<Row> {
969    /// Returns `true` if the first column at `offset` is NULL.
970    ///
971    /// # Errors
972    ///
973    /// Returns an error if the row cannot be inspected at `offset` (e.g. the
974    /// driver reports an out-of-range index or conversion failure).
975    fn is_null_at(row: &Row, offset: usize) -> Result<bool, DrizzleError>;
976}
977
978// -- Tuple impls: generic over Row, composing inner impls --
979
980macro_rules! impl_from_drizzle_row_tuple {
981    ($($T:ident),+; $($idx:tt),+) => {
982        impl<__Row: ?Sized, $($T: FromDrizzleRow<__Row>),+> FromDrizzleRow<__Row> for ($($T,)+) {
983            const COLUMN_COUNT: usize = 0 $(+ <$T as FromDrizzleRow<__Row>>::COLUMN_COUNT)+;
984
985            #[allow(non_snake_case)]
986            fn from_row_at(
987                row: &__Row,
988                offset: usize,
989            ) -> Result<Self, DrizzleError> {
990                let mut __off = offset;
991                $(
992                    let $T = <$T as FromDrizzleRow<__Row>>::from_row_at(row, __off)?;
993                    __off += <$T as FromDrizzleRow<__Row>>::COLUMN_COUNT;
994                )+
995                Ok(($($T,)+))
996            }
997        }
998    };
999}
1000
1001with_col_sizes_8!(impl_from_drizzle_row_tuple);
1002
1003#[cfg(any(
1004    feature = "col16",
1005    feature = "col32",
1006    feature = "col64",
1007    feature = "col128",
1008    feature = "col200"
1009))]
1010with_col_sizes_16!(impl_from_drizzle_row_tuple);
1011
1012#[cfg(any(
1013    feature = "col32",
1014    feature = "col64",
1015    feature = "col128",
1016    feature = "col200"
1017))]
1018with_col_sizes_32!(impl_from_drizzle_row_tuple);
1019
1020#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1021with_col_sizes_64!(impl_from_drizzle_row_tuple);
1022
1023#[cfg(any(feature = "col128", feature = "col200"))]
1024with_col_sizes_128!(impl_from_drizzle_row_tuple);
1025
1026#[cfg(feature = "col200")]
1027with_col_sizes_200!(impl_from_drizzle_row_tuple);
1028
1029// =============================================================================
1030// SQLTypeToRust — SQL type marker × dialect → canonical Rust type
1031// =============================================================================
1032
1033/// Maps a dialect-native SQL type marker to its canonical Rust type.
1034///
1035/// Parameterized by `D` (a dialect marker such as
1036/// [`SQLiteDialect`](crate::dialect::SQLiteDialect) or
1037/// [`PostgresDialect`](crate::dialect::PostgresDialect)) so that
1038/// type mappings can differ per database.
1039///
1040/// Each dialect's native type markers (e.g., `sqlite::types::Integer`,
1041/// `postgres::types::Int4`) implement this trait for their respective dialect.
1042///
1043/// Feature-gated types (`chrono`, `uuid`, `serde`) provide mappings when
1044/// the feature is enabled. Without the feature there is **no impl**,
1045/// producing a compile error that guides the user.
1046#[diagnostic::on_unimplemented(
1047    message = "SQL type `{Self}` has no default Rust mapping for dialect `{D}`",
1048    label = "this SQL type has no default Rust mapping for this dialect",
1049    note = "enable `chrono` for Date/Time/Timestamp/TimestampTz, `uuid` for Uuid, or `serde` for Json/Jsonb"
1050)]
1051pub trait SQLTypeToRust<D> {
1052    type RustType;
1053}
1054
1055// -- Dialect-native mappings ---------------------------------------------------
1056
1057use crate::dialect::{PostgresDialect, SQLiteDialect};
1058
1059impl<D, T> SQLTypeToRust<D> for crate::types::Array<T>
1060where
1061    T: crate::types::DataType + SQLTypeToRust<D>,
1062{
1063    type RustType = crate::prelude::Vec<<T as SQLTypeToRust<D>>::RustType>;
1064}
1065
1066impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Integer {
1067    type RustType = i64;
1068}
1069
1070impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Text {
1071    type RustType = crate::prelude::String;
1072}
1073
1074impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Real {
1075    type RustType = f64;
1076}
1077
1078impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Blob {
1079    type RustType = crate::prelude::Vec<u8>;
1080}
1081
1082impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Numeric {
1083    type RustType = f64;
1084}
1085
1086impl SQLTypeToRust<SQLiteDialect> for drizzle_types::sqlite::types::Any {
1087    type RustType = crate::prelude::String;
1088}
1089
1090impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Int2 {
1091    type RustType = i16;
1092}
1093
1094impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Int4 {
1095    type RustType = i32;
1096}
1097
1098impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Int8 {
1099    type RustType = i64;
1100}
1101
1102impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Float4 {
1103    type RustType = f32;
1104}
1105
1106impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Float8 {
1107    type RustType = f64;
1108}
1109
1110impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Varchar {
1111    type RustType = crate::prelude::String;
1112}
1113
1114impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Text {
1115    type RustType = crate::prelude::String;
1116}
1117
1118impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Char {
1119    type RustType = crate::prelude::String;
1120}
1121
1122impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Bytea {
1123    type RustType = crate::prelude::Vec<u8>;
1124}
1125
1126impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Boolean {
1127    type RustType = bool;
1128}
1129
1130#[cfg(feature = "rust-decimal")]
1131impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Numeric {
1132    type RustType = rust_decimal::Decimal;
1133}
1134
1135#[cfg(not(feature = "rust-decimal"))]
1136impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Numeric {
1137    type RustType = crate::prelude::String;
1138}
1139
1140impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Any {
1141    type RustType = crate::prelude::String;
1142}
1143
1144#[cfg(feature = "chrono")]
1145impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamptz {
1146    type RustType = chrono::DateTime<chrono::Utc>;
1147}
1148
1149#[cfg(feature = "chrono")]
1150impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timestamp {
1151    type RustType = chrono::NaiveDateTime;
1152}
1153
1154#[cfg(feature = "chrono")]
1155impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Date {
1156    type RustType = chrono::NaiveDate;
1157}
1158
1159#[cfg(feature = "chrono")]
1160impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Time {
1161    type RustType = chrono::NaiveTime;
1162}
1163
1164#[cfg(feature = "chrono")]
1165impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Timetz {
1166    type RustType = chrono::NaiveTime;
1167}
1168
1169#[cfg(feature = "uuid")]
1170impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Uuid {
1171    type RustType = uuid::Uuid;
1172}
1173
1174#[cfg(feature = "serde")]
1175impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Json {
1176    type RustType = serde_json::Value;
1177}
1178
1179#[cfg(feature = "serde")]
1180impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Jsonb {
1181    type RustType = serde_json::Value;
1182}
1183
1184// -- Feature-gated type marker mappings --
1185
1186#[cfg(feature = "chrono")]
1187impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Interval {
1188    type RustType = chrono::Duration;
1189}
1190
1191#[cfg(not(feature = "chrono"))]
1192impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Interval {
1193    type RustType = crate::prelude::String;
1194}
1195
1196#[cfg(feature = "cidr")]
1197impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Inet {
1198    type RustType = cidr::IpInet;
1199}
1200
1201#[cfg(not(feature = "cidr"))]
1202impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Inet {
1203    type RustType = crate::prelude::String;
1204}
1205
1206#[cfg(feature = "cidr")]
1207impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Cidr {
1208    type RustType = cidr::IpCidr;
1209}
1210
1211#[cfg(not(feature = "cidr"))]
1212impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Cidr {
1213    type RustType = crate::prelude::String;
1214}
1215
1216impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::MacAddr {
1217    type RustType = crate::prelude::String;
1218}
1219
1220impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::MacAddr8 {
1221    type RustType = crate::prelude::String;
1222}
1223
1224#[cfg(feature = "geo-types")]
1225impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Point {
1226    type RustType = geo_types::Point<f64>;
1227}
1228
1229#[cfg(not(feature = "geo-types"))]
1230impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Point {
1231    type RustType = crate::prelude::String;
1232}
1233
1234#[cfg(feature = "geo-types")]
1235impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::LineString {
1236    type RustType = geo_types::LineString<f64>;
1237}
1238
1239#[cfg(not(feature = "geo-types"))]
1240impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::LineString {
1241    type RustType = crate::prelude::String;
1242}
1243
1244#[cfg(feature = "geo-types")]
1245impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Rect {
1246    type RustType = geo_types::Rect<f64>;
1247}
1248
1249#[cfg(not(feature = "geo-types"))]
1250impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Rect {
1251    type RustType = crate::prelude::String;
1252}
1253
1254#[cfg(feature = "bit-vec")]
1255impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::BitString {
1256    type RustType = bit_vec::BitVec;
1257}
1258
1259#[cfg(not(feature = "bit-vec"))]
1260impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::BitString {
1261    type RustType = crate::prelude::String;
1262}
1263
1264impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Line {
1265    type RustType = crate::prelude::String;
1266}
1267
1268impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::LineSegment {
1269    type RustType = crate::prelude::String;
1270}
1271
1272impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Polygon {
1273    type RustType = crate::prelude::String;
1274}
1275
1276impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Circle {
1277    type RustType = crate::prelude::String;
1278}
1279
1280impl SQLTypeToRust<PostgresDialect> for drizzle_types::postgres::types::Enum {
1281    type RustType = crate::prelude::String;
1282}
1283
1284// =============================================================================
1285// WrapNullable — Option<T> wrapping based on nullability
1286// =============================================================================
1287
1288/// Wraps a Rust type in `Option<T>` when nullable.
1289pub trait WrapNullable<T> {
1290    type Output;
1291}
1292
1293impl<T> WrapNullable<T> for crate::expr::NonNull {
1294    type Output = T;
1295}
1296
1297impl<T> WrapNullable<T> for crate::expr::Null {
1298    type Output = Option<T>;
1299}
1300
1301// =============================================================================
1302// ExprValueType — "what Rust type does this expression produce?"
1303// =============================================================================
1304
1305/// Resolves the Rust value type for a column or typed expression.
1306///
1307/// Implemented for:
1308/// - Column ZSTs (proc macro generates alongside `ColumnValueType`)
1309/// - `SQLExpr<T, N, A>` where `T: SQLTypeToRust<D>` and `N: WrapNullable`
1310///
1311/// For `SQL<'a, V>` (raw SQL), `ValueType = ()` — the user must specify
1312/// the concrete row type via turbofish (`.all::<T>()`).
1313#[diagnostic::on_unimplemented(
1314    message = "cannot infer Rust type for expression `{Self}`",
1315    label = "use typed expressions or derive FromRow to specify the Rust type",
1316    note = "raw SQL and JSON expressions require explicit type annotation"
1317)]
1318pub trait ExprValueType {
1319    type ValueType;
1320}
1321
1322impl<V: crate::SQLParam, T, N, A> ExprValueType for crate::expr::SQLExpr<'_, V, T, N, A>
1323where
1324    T: crate::types::DataType + SQLTypeToRust<V::DialectMarker>,
1325    N: crate::expr::Nullability + WrapNullable<<T as SQLTypeToRust<V::DialectMarker>>::RustType>,
1326    A: crate::expr::AggregateKind,
1327{
1328    type ValueType = <N as WrapNullable<<T as SQLTypeToRust<V::DialectMarker>>::RustType>>::Output;
1329}
1330
1331/// Raw SQL fallback — value type is `()`, user must specify the concrete type.
1332impl<V: crate::SQLParam> ExprValueType for crate::sql::SQL<'_, V> {
1333    type ValueType = ();
1334}
1335
1336// =============================================================================
1337// HasSelectModel — table → Select model (lifetime-free)
1338// =============================================================================
1339
1340/// Associates a table with its Select model type and column count.
1341///
1342/// Generated by `#[SQLiteTable]` / `#[PostgresTable]` alongside `SQLTable`.
1343#[diagnostic::on_unimplemented(
1344    message = "`{Self}` is not a drizzle table",
1345    label = "ensure this type was derived with #[SQLiteTable] or #[PostgresTable]"
1346)]
1347pub trait HasSelectModel {
1348    type SelectModel;
1349    const COLUMN_COUNT: usize;
1350}
1351
1352// =============================================================================
1353// ResolveRow — Marker + Table → default row type R
1354// =============================================================================
1355
1356/// Given a select marker and a table, determines the default row type R.
1357/// Evaluated at `.from(table)` time.
1358#[diagnostic::on_unimplemented(
1359    message = "cannot resolve return type for this query",
1360    label = "the selected columns and table do not produce a known row type"
1361)]
1362pub trait ResolveRow<Table> {
1363    type Row;
1364}
1365
1366impl<T: HasSelectModel> ResolveRow<T> for SelectStar {
1367    type Row = T::SelectModel;
1368}
1369
1370impl<T> ResolveRow<T> for SelectExpr {
1371    type Row = ();
1372}
1373
1374impl<R, T> ResolveRow<T> for SelectAs<R>
1375where
1376    R: SelectAsFrom<T>,
1377{
1378    type Row = R;
1379}
1380
1381impl<M, Scope, T> ResolveRow<T> for Scoped<M, Scope>
1382where
1383    M: ResolveRow<T>,
1384{
1385    type Row = M::Row;
1386}
1387
1388/// Compile-time constraint for `.select(MyRow::Select).from(table)` base table matching.
1389///
1390/// `#[from(Table)]` on `*FromRow` structs emits `impl SelectAsFrom<Table> for MyRow`.
1391/// Structs without `#[from(...)]` may opt into any table.
1392#[diagnostic::on_unimplemented(
1393    message = "row selector `{Self}` cannot be used with table `{Table}`",
1394    label = "the #[from(...)] table does not match .from(...)",
1395    note = "set #[from(TheTable)] to the same table passed to .from(...)"
1396)]
1397pub trait SelectAsFrom<Table> {}
1398
1399// -- SelectCols: column value types → row tuple --
1400
1401macro_rules! impl_resolve_row_cols {
1402    ($($T:ident),+; $($idx:tt),+) => {
1403        impl<__Table, $($T: ExprValueType),+> ResolveRow<__Table> for SelectCols<($($T,)+)> {
1404            type Row = ($(<$T as ExprValueType>::ValueType,)+);
1405        }
1406    };
1407}
1408
1409with_col_sizes_8!(impl_resolve_row_cols);
1410
1411#[cfg(any(
1412    feature = "col16",
1413    feature = "col32",
1414    feature = "col64",
1415    feature = "col128",
1416    feature = "col200"
1417))]
1418with_col_sizes_16!(impl_resolve_row_cols);
1419
1420#[cfg(any(
1421    feature = "col32",
1422    feature = "col64",
1423    feature = "col128",
1424    feature = "col200"
1425))]
1426with_col_sizes_32!(impl_resolve_row_cols);
1427
1428#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1429with_col_sizes_64!(impl_resolve_row_cols);
1430
1431#[cfg(any(feature = "col128", feature = "col200"))]
1432with_col_sizes_128!(impl_resolve_row_cols);
1433
1434#[cfg(feature = "col200")]
1435with_col_sizes_200!(impl_resolve_row_cols);
1436
1437macro_rules! selected_columns_cons {
1438    () => {
1439        crate::Nil
1440    };
1441    ($head:ident $(, $tail:ident)*) => {
1442        crate::Cons<<$head as ExprValueType>::ValueType, selected_columns_cons!($($tail),*)>
1443    };
1444}
1445
1446macro_rules! impl_selected_column_list_tuple {
1447    ($($T:ident),+; $($idx:tt),+) => {
1448        impl<$($T: ExprValueType),+> SelectedColumnList for ($($T,)+) {
1449            type Columns = selected_columns_cons!($($T),+);
1450        }
1451    };
1452}
1453
1454with_col_sizes_8!(impl_selected_column_list_tuple);
1455
1456#[cfg(any(
1457    feature = "col16",
1458    feature = "col32",
1459    feature = "col64",
1460    feature = "col128",
1461    feature = "col200"
1462))]
1463with_col_sizes_16!(impl_selected_column_list_tuple);
1464
1465#[cfg(any(
1466    feature = "col32",
1467    feature = "col64",
1468    feature = "col128",
1469    feature = "col200"
1470))]
1471with_col_sizes_32!(impl_selected_column_list_tuple);
1472
1473#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1474with_col_sizes_64!(impl_selected_column_list_tuple);
1475
1476#[cfg(any(feature = "col128", feature = "col200"))]
1477with_col_sizes_128!(impl_selected_column_list_tuple);
1478
1479#[cfg(feature = "col200")]
1480with_col_sizes_200!(impl_selected_column_list_tuple);
1481
1482// =============================================================================
1483// AfterJoin — how joins transform the row type
1484// =============================================================================
1485
1486/// Determines the new row type after a JOIN.
1487pub trait AfterJoin<CurrentRow, JoinedTable> {
1488    type NewRow;
1489}
1490
1491/// Determines the new row type after a LEFT JOIN.
1492pub trait AfterLeftJoin<CurrentRow, JoinedTable> {
1493    type NewRow;
1494}
1495
1496/// Determines the new row type after a RIGHT JOIN.
1497pub trait AfterRightJoin<CurrentRow, JoinedTable> {
1498    type NewRow;
1499}
1500
1501/// Determines the new row type after a FULL JOIN.
1502pub trait AfterFullJoin<CurrentRow, JoinedTable> {
1503    type NewRow;
1504}
1505
1506/// `SELECT *` + JOIN → `(CurrentRow, JoinedTable::SelectModel)`.
1507impl<R, T: HasSelectModel> AfterJoin<R, T> for SelectStar {
1508    type NewRow = (R, T::SelectModel);
1509}
1510
1511/// `SELECT *` + LEFT JOIN → `(CurrentRow, Option<JoinedTable::SelectModel>)`.
1512impl<R, T: HasSelectModel> AfterLeftJoin<R, T> for SelectStar {
1513    type NewRow = (R, Option<T::SelectModel>);
1514}
1515
1516/// `SELECT *` + RIGHT JOIN → `(Option<CurrentRow>, JoinedTable::SelectModel)`.
1517impl<R, T: HasSelectModel> AfterRightJoin<R, T> for SelectStar {
1518    type NewRow = (Option<R>, T::SelectModel);
1519}
1520
1521/// `SELECT *` + FULL JOIN → `(Option<CurrentRow>, Option<JoinedTable::SelectModel>)`.
1522impl<R, T: HasSelectModel> AfterFullJoin<R, T> for SelectStar {
1523    type NewRow = (Option<R>, Option<T::SelectModel>);
1524}
1525
1526/// Explicit columns + JOIN → R unchanged.
1527impl<Cols, R, T> AfterJoin<R, T> for SelectCols<Cols> {
1528    type NewRow = R;
1529}
1530
1531impl<Cols, R, T> AfterLeftJoin<R, T> for SelectCols<Cols> {
1532    type NewRow = R;
1533}
1534
1535impl<Cols, R, T> AfterRightJoin<R, T> for SelectCols<Cols> {
1536    type NewRow = R;
1537}
1538
1539impl<Cols, R, T> AfterFullJoin<R, T> for SelectCols<Cols> {
1540    type NewRow = R;
1541}
1542
1543/// Raw/untyped + JOIN → R unchanged.
1544impl<R, T> AfterJoin<R, T> for SelectExpr {
1545    type NewRow = R;
1546}
1547
1548impl<R, T> AfterLeftJoin<R, T> for SelectExpr {
1549    type NewRow = R;
1550}
1551
1552impl<R, T> AfterRightJoin<R, T> for SelectExpr {
1553    type NewRow = R;
1554}
1555
1556impl<R, T> AfterFullJoin<R, T> for SelectExpr {
1557    type NewRow = R;
1558}
1559
1560/// Explicit model + JOIN → R unchanged.
1561impl<Row, R, T> AfterJoin<R, T> for SelectAs<Row> {
1562    type NewRow = R;
1563}
1564
1565impl<Row, R, T> AfterLeftJoin<R, T> for SelectAs<Row> {
1566    type NewRow = R;
1567}
1568
1569impl<Row, R, T> AfterRightJoin<R, T> for SelectAs<Row> {
1570    type NewRow = R;
1571}
1572
1573impl<Row, R, T> AfterFullJoin<R, T> for SelectAs<Row> {
1574    type NewRow = R;
1575}
1576
1577impl<M, Scope, R, T> AfterJoin<R, T> for Scoped<M, Scope>
1578where
1579    M: AfterJoin<R, T>,
1580{
1581    type NewRow = M::NewRow;
1582}
1583
1584impl<M, Scope, R, T> AfterLeftJoin<R, T> for Scoped<M, Scope>
1585where
1586    M: AfterLeftJoin<R, T>,
1587{
1588    type NewRow = M::NewRow;
1589}
1590
1591impl<M, Scope, R, T> AfterRightJoin<R, T> for Scoped<M, Scope>
1592where
1593    M: AfterRightJoin<R, T>,
1594{
1595    type NewRow = M::NewRow;
1596}
1597
1598impl<M, Scope, R, T> AfterFullJoin<R, T> for Scoped<M, Scope>
1599where
1600    M: AfterFullJoin<R, T>,
1601{
1602    type NewRow = M::NewRow;
1603}
1604
1605// =============================================================================
1606// IntoSelectTarget — select arguments → Marker type
1607// =============================================================================
1608
1609/// Determines the select marker from what was passed to `.select()`.
1610///
1611/// The marker controls how row types are inferred:
1612/// - `SelectStar` — infer R from the table's Select model
1613/// - `SelectCols<C>` — infer R from the column value types
1614/// - `SelectExpr` — R must be specified by the user
1615///
1616/// Implemented automatically for:
1617/// - `()` → `SelectStar`
1618/// - `SQL<'a, V>` → `SelectExpr`
1619/// - `SQLExpr<'a, V, T, N, A>` → `SelectCols<(Self,)>`
1620/// - Tuples `(A, B, ...)` → `SelectCols<(A, B, ...)>`
1621/// - Column ZSTs (proc macro generated)
1622/// - Table structs (proc macro generated) → `SelectStar`
1623#[diagnostic::on_unimplemented(
1624    message = "`{Self}` cannot be used as a select target",
1625    label = "this type does not implement IntoSelectTarget",
1626    note = "implement IntoSelectTarget or use a column, table, or typed expression"
1627)]
1628pub trait IntoSelectTarget {
1629    type Marker;
1630}
1631
1632/// `select(())` → `SelectStar` — infer row type from the table.
1633impl IntoSelectTarget for () {
1634    type Marker = SelectStar;
1635}
1636
1637/// `select(sql!(...))` → `SelectExpr` — user must specify row type.
1638impl<V: crate::SQLParam> IntoSelectTarget for crate::sql::SQL<'_, V> {
1639    type Marker = SelectExpr;
1640}
1641
1642/// `select(typed_expr)` → `SelectCols<(Expr,)>` — single typed expression.
1643impl<V: crate::SQLParam, T, N, A> IntoSelectTarget for crate::expr::SQLExpr<'_, V, T, N, A>
1644where
1645    T: crate::types::DataType,
1646    N: crate::expr::Nullability,
1647    A: crate::expr::AggregateKind,
1648{
1649    type Marker = SelectCols<(Self,)>;
1650}
1651
1652/// Tuples of select targets → `SelectCols<(A, B, ...)>`.
1653macro_rules! impl_into_select_target_tuple {
1654    ($($T:ident),+; $($idx:tt),+) => {
1655        impl<$($T),+> IntoSelectTarget for ($($T,)+) {
1656            type Marker = SelectCols<($($T,)+)>;
1657        }
1658    };
1659}
1660
1661with_col_sizes_8!(impl_into_select_target_tuple);
1662
1663#[cfg(any(
1664    feature = "col16",
1665    feature = "col32",
1666    feature = "col64",
1667    feature = "col128",
1668    feature = "col200"
1669))]
1670with_col_sizes_16!(impl_into_select_target_tuple);
1671
1672#[cfg(any(
1673    feature = "col32",
1674    feature = "col64",
1675    feature = "col128",
1676    feature = "col200"
1677))]
1678with_col_sizes_32!(impl_into_select_target_tuple);
1679
1680#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1681with_col_sizes_64!(impl_into_select_target_tuple);
1682
1683#[cfg(any(feature = "col128", feature = "col200"))]
1684with_col_sizes_128!(impl_into_select_target_tuple);
1685
1686#[cfg(feature = "col200")]
1687with_col_sizes_200!(impl_into_select_target_tuple);