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