Skip to main content

drizzle_types/sql/
mod.rs

1//! SQL data type markers for compile-time type safety.
2//!
3//! This module provides zero-sized type markers that represent SQL data types
4//! at the Rust type level, enabling the type system to verify compatible
5//! comparisons and operations at compile time.
6
7use core::marker::PhantomData;
8
9mod coerce;
10mod ops;
11
12pub use coerce::*;
13pub use ops::*;
14
15mod private {
16    pub trait Sealed {}
17}
18
19/// Represents a SQL data type at the type level.
20#[diagnostic::on_unimplemented(
21    message = "`{Self}` is not a recognized SQL data type",
22    label = "use a drizzle SQL type marker (Int, Text, Bool, etc.)"
23)]
24pub trait DataType: private::Sealed + Copy + 'static {}
25
26/// Numeric SQL types that support arithmetic operations (+, -, *, /).
27#[diagnostic::on_unimplemented(
28    message = "`{Self}` is not a numeric SQL type",
29    label = "arithmetic operations require Int, SmallInt, BigInt, Float, or Double"
30)]
31pub trait Numeric: DataType {}
32
33/// Integer SQL types (SMALLINT, INTEGER, BIGINT).
34#[diagnostic::on_unimplemented(
35    message = "`{Self}` is not an integer SQL type",
36    label = "expected SmallInt, Int, or BigInt"
37)]
38pub trait Integral: Numeric {}
39
40/// Floating-point SQL types (REAL, DOUBLE PRECISION).
41#[diagnostic::on_unimplemented(
42    message = "`{Self}` is not a floating-point SQL type",
43    label = "expected Float or Double"
44)]
45pub trait Floating: Numeric {}
46
47/// String/text SQL types (TEXT, VARCHAR, CHAR).
48#[diagnostic::on_unimplemented(
49    message = "`{Self}` is not a text SQL type",
50    label = "expected Text or VarChar"
51)]
52pub trait Textual: DataType {}
53
54/// Binary data types (BLOB, BYTEA).
55#[diagnostic::on_unimplemented(
56    message = "`{Self}` is not a binary SQL type",
57    label = "expected Bytes (BLOB/BYTEA)"
58)]
59pub trait Binary: DataType {}
60
61/// Temporal SQL types (DATE, TIME, TIMESTAMP).
62#[diagnostic::on_unimplemented(
63    message = "`{Self}` is not a temporal SQL type",
64    label = "expected Date, Time, Timestamp, or TimestampTz"
65)]
66pub trait Temporal: DataType {}
67
68/// Boolean-like SQL types that support logical operations (NOT, AND, OR).
69#[diagnostic::on_unimplemented(
70    message = "`{Self}` is not a boolean SQL type",
71    label = "logical operations require a boolean-typed expression"
72)]
73pub trait BooleanLike: DataType {}
74
75/// PostgreSQL-style SQL array type marker.
76///
77/// `Array<T>` represents an array whose element SQL type is `T`.
78#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
79pub struct Array<T: DataType>(pub PhantomData<T>);
80
81/// Placeholder marker used for bind parameters before concrete typing.
82#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
83pub struct Placeholder;
84
85/// The SQL type of a condition list — a tuple of conditions combined with AND.
86///
87/// Boolean-like, so a condition list is accepted anywhere a condition is, but
88/// deliberately **not** [`Compatible`] with
89/// itself. A condition list occupies one expression slot rather than one column
90/// slot, and self-incompatibility is what lets APIs that accept either a single
91/// column or a tuple of columns (`IN (subquery)` row values) tell the two apart.
92#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
93pub struct Conjunction;
94
95impl<T: DataType> private::Sealed for Array<T> {}
96impl<T: DataType> DataType for Array<T> {}
97impl private::Sealed for Placeholder {}
98impl DataType for Placeholder {}
99impl Textual for Placeholder {}
100impl private::Sealed for Conjunction {}
101impl DataType for Conjunction {}
102impl BooleanLike for Conjunction {}
103
104// =============================================================================
105// SQLite dialect marker impls
106// =============================================================================
107
108impl private::Sealed for crate::sqlite::types::Integer {}
109impl private::Sealed for crate::sqlite::types::Text {}
110impl private::Sealed for crate::sqlite::types::Real {}
111impl private::Sealed for crate::sqlite::types::Blob {}
112impl private::Sealed for crate::sqlite::types::Numeric {}
113impl private::Sealed for crate::sqlite::types::Any {}
114
115impl DataType for crate::sqlite::types::Integer {}
116impl DataType for crate::sqlite::types::Text {}
117impl DataType for crate::sqlite::types::Real {}
118impl DataType for crate::sqlite::types::Blob {}
119impl DataType for crate::sqlite::types::Numeric {}
120impl DataType for crate::sqlite::types::Any {}
121
122impl Numeric for crate::sqlite::types::Integer {}
123impl Numeric for crate::sqlite::types::Real {}
124impl Numeric for crate::sqlite::types::Numeric {}
125impl Numeric for crate::sqlite::types::Any {}
126
127impl Integral for crate::sqlite::types::Integer {}
128
129impl Floating for crate::sqlite::types::Real {}
130
131impl Textual for crate::sqlite::types::Text {}
132impl Textual for crate::sqlite::types::Any {}
133
134impl Binary for crate::sqlite::types::Blob {}
135
136impl Temporal for crate::sqlite::types::Integer {}
137impl Temporal for crate::sqlite::types::Real {}
138impl Temporal for crate::sqlite::types::Text {}
139impl Temporal for crate::sqlite::types::Numeric {}
140
141impl BooleanLike for crate::sqlite::types::Integer {}
142
143// =============================================================================
144// PostgreSQL dialect marker impls
145// =============================================================================
146
147impl private::Sealed for crate::postgres::types::Int2 {}
148impl private::Sealed for crate::postgres::types::Int4 {}
149impl private::Sealed for crate::postgres::types::Int8 {}
150impl private::Sealed for crate::postgres::types::Float4 {}
151impl private::Sealed for crate::postgres::types::Float8 {}
152impl private::Sealed for crate::postgres::types::Varchar {}
153impl private::Sealed for crate::postgres::types::Text {}
154impl private::Sealed for crate::postgres::types::Char {}
155impl private::Sealed for crate::postgres::types::Bytea {}
156impl private::Sealed for crate::postgres::types::Boolean {}
157impl private::Sealed for crate::postgres::types::Timestamptz {}
158impl private::Sealed for crate::postgres::types::Timestamp {}
159impl private::Sealed for crate::postgres::types::Date {}
160impl private::Sealed for crate::postgres::types::Time {}
161impl private::Sealed for crate::postgres::types::Timetz {}
162impl private::Sealed for crate::postgres::types::Numeric {}
163impl private::Sealed for crate::postgres::types::Uuid {}
164impl private::Sealed for crate::postgres::types::Json {}
165impl private::Sealed for crate::postgres::types::Jsonb {}
166impl private::Sealed for crate::postgres::types::Any {}
167impl private::Sealed for crate::postgres::types::Interval {}
168impl private::Sealed for crate::postgres::types::Inet {}
169impl private::Sealed for crate::postgres::types::Cidr {}
170impl private::Sealed for crate::postgres::types::MacAddr {}
171impl private::Sealed for crate::postgres::types::MacAddr8 {}
172impl private::Sealed for crate::postgres::types::Point {}
173impl private::Sealed for crate::postgres::types::LineString {}
174impl private::Sealed for crate::postgres::types::Rect {}
175impl private::Sealed for crate::postgres::types::BitString {}
176impl private::Sealed for crate::postgres::types::Line {}
177impl private::Sealed for crate::postgres::types::LineSegment {}
178impl private::Sealed for crate::postgres::types::Polygon {}
179impl private::Sealed for crate::postgres::types::Circle {}
180impl private::Sealed for crate::postgres::types::Enum {}
181
182impl DataType for crate::postgres::types::Int2 {}
183impl DataType for crate::postgres::types::Int4 {}
184impl DataType for crate::postgres::types::Int8 {}
185impl DataType for crate::postgres::types::Float4 {}
186impl DataType for crate::postgres::types::Float8 {}
187impl DataType for crate::postgres::types::Varchar {}
188impl DataType for crate::postgres::types::Text {}
189impl DataType for crate::postgres::types::Char {}
190impl DataType for crate::postgres::types::Bytea {}
191impl DataType for crate::postgres::types::Boolean {}
192impl DataType for crate::postgres::types::Timestamptz {}
193impl DataType for crate::postgres::types::Timestamp {}
194impl DataType for crate::postgres::types::Date {}
195impl DataType for crate::postgres::types::Time {}
196impl DataType for crate::postgres::types::Timetz {}
197impl DataType for crate::postgres::types::Numeric {}
198impl DataType for crate::postgres::types::Uuid {}
199impl DataType for crate::postgres::types::Json {}
200impl DataType for crate::postgres::types::Jsonb {}
201impl DataType for crate::postgres::types::Any {}
202impl DataType for crate::postgres::types::Interval {}
203impl DataType for crate::postgres::types::Inet {}
204impl DataType for crate::postgres::types::Cidr {}
205impl DataType for crate::postgres::types::MacAddr {}
206impl DataType for crate::postgres::types::MacAddr8 {}
207impl DataType for crate::postgres::types::Point {}
208impl DataType for crate::postgres::types::LineString {}
209impl DataType for crate::postgres::types::Rect {}
210impl DataType for crate::postgres::types::BitString {}
211impl DataType for crate::postgres::types::Line {}
212impl DataType for crate::postgres::types::LineSegment {}
213impl DataType for crate::postgres::types::Polygon {}
214impl DataType for crate::postgres::types::Circle {}
215impl DataType for crate::postgres::types::Enum {}
216
217impl Numeric for crate::postgres::types::Int2 {}
218impl Numeric for crate::postgres::types::Int4 {}
219impl Numeric for crate::postgres::types::Int8 {}
220impl Numeric for crate::postgres::types::Float4 {}
221impl Numeric for crate::postgres::types::Float8 {}
222impl Numeric for crate::postgres::types::Numeric {}
223
224impl Integral for crate::postgres::types::Int2 {}
225impl Integral for crate::postgres::types::Int4 {}
226impl Integral for crate::postgres::types::Int8 {}
227
228impl Floating for crate::postgres::types::Float4 {}
229impl Floating for crate::postgres::types::Float8 {}
230
231impl Textual for crate::postgres::types::Varchar {}
232impl Textual for crate::postgres::types::Text {}
233impl Textual for crate::postgres::types::Char {}
234impl Textual for crate::postgres::types::Enum {}
235
236impl Binary for crate::postgres::types::Bytea {}
237
238impl Temporal for crate::postgres::types::Timestamptz {}
239impl Temporal for crate::postgres::types::Timestamp {}
240impl Temporal for crate::postgres::types::Date {}
241impl Temporal for crate::postgres::types::Time {}
242impl Temporal for crate::postgres::types::Timetz {}
243
244impl Temporal for crate::postgres::types::Interval {}
245
246impl BooleanLike for crate::postgres::types::Boolean {}
247
248// =============================================================================
249// MySQL dialect marker impls
250// =============================================================================
251
252macro_rules! impl_mysql_data_types {
253    ($($marker:ident),+ $(,)?) => {
254        $(
255            impl private::Sealed for crate::mysql::types::$marker {}
256            impl DataType for crate::mysql::types::$marker {}
257        )+
258    };
259}
260
261impl_mysql_data_types!(
262    TinyInt,
263    TinyIntUnsigned,
264    SmallInt,
265    SmallIntUnsigned,
266    MediumInt,
267    MediumIntUnsigned,
268    Int,
269    IntUnsigned,
270    BigInt,
271    BigIntUnsigned,
272    Float,
273    Double,
274    Decimal,
275    Boolean,
276    Char,
277    Varchar,
278    TinyText,
279    Text,
280    MediumText,
281    LongText,
282    Binary,
283    Varbinary,
284    TinyBlob,
285    Blob,
286    MediumBlob,
287    LongBlob,
288    Json,
289    Date,
290    Time,
291    DateTime,
292    Timestamp,
293    Year,
294    Enum,
295    Set,
296    Bit,
297    Any,
298);
299
300macro_rules! impl_mysql_marker_trait {
301    ($trait:ident; $($marker:ident),+ $(,)?) => {
302        $(impl $trait for crate::mysql::types::$marker {})+
303    };
304}
305
306impl_mysql_marker_trait!(Numeric;
307    TinyInt,
308    TinyIntUnsigned,
309    SmallInt,
310    SmallIntUnsigned,
311    MediumInt,
312    MediumIntUnsigned,
313    Int,
314    IntUnsigned,
315    BigInt,
316    BigIntUnsigned,
317    Year,
318    Float,
319    Double,
320    Decimal,
321);
322
323impl_mysql_marker_trait!(Integral;
324    TinyInt,
325    TinyIntUnsigned,
326    SmallInt,
327    SmallIntUnsigned,
328    MediumInt,
329    MediumIntUnsigned,
330    Int,
331    IntUnsigned,
332    BigInt,
333    BigIntUnsigned,
334    Year,
335);
336
337impl Floating for crate::mysql::types::Float {}
338impl Floating for crate::mysql::types::Double {}
339
340impl_mysql_marker_trait!(Textual;
341    Char, Varchar, TinyText, Text, MediumText, LongText, Enum, Set,
342);
343
344impl_mysql_marker_trait!(Binary; Binary, Varbinary, TinyBlob, Blob, MediumBlob, LongBlob, Bit,);
345
346impl Temporal for crate::mysql::types::Date {}
347impl Temporal for crate::mysql::types::Time {}
348impl Temporal for crate::mysql::types::DateTime {}
349impl Temporal for crate::mysql::types::Timestamp {}
350
351impl BooleanLike for crate::mysql::types::Boolean {}
352
353// =============================================================================
354// Tuple SQL type markers
355// =============================================================================
356
357macro_rules! seq_tuples {
358    (@acc $callback:ident [$($aT:ident),*] [$($ai:tt),*]) => {};
359    (@acc $callback:ident [$($aT:ident),*] [$($ai:tt),*] ($T:ident, $i:tt) $($rest:tt)*) => {
360        $callback!($($aT,)* $T; $($ai,)* $i);
361        seq_tuples!(@acc $callback [$($aT,)* $T] [$($ai,)* $i] $($rest)*);
362    };
363    ($callback:ident; $($pairs:tt)+) => {
364        seq_tuples!(@acc $callback [] [] $($pairs)+);
365    };
366    (@from $callback:ident [$($aT:ident),*] [$($ai:tt),*]; $($pairs:tt)+) => {
367        seq_tuples!(@acc $callback [$($aT),*] [$($ai),*] $($pairs)+);
368    };
369}
370
371macro_rules! with_col_sizes_8 {
372    ($callback:ident) => {
373        seq_tuples!($callback;
374            (T0,0) (T1,1) (T2,2) (T3,3)
375            (T4,4) (T5,5) (T6,6) (T7,7)
376        );
377    };
378}
379
380#[allow(unused_macros)]
381macro_rules! with_col_sizes_16 {
382    ($callback:ident) => {
383        seq_tuples!(@from $callback
384            [T0,T1,T2,T3,T4,T5,T6,T7]
385            [0,1,2,3,4,5,6,7];
386            (T8,8) (T9,9) (T10,10) (T11,11)
387            (T12,12) (T13,13) (T14,14) (T15,15)
388        );
389    };
390}
391
392#[allow(unused_macros)]
393macro_rules! with_col_sizes_32 {
394    ($callback:ident) => {
395        seq_tuples!(@from $callback
396            [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15]
397            [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
398            (T16,16) (T17,17) (T18,18) (T19,19)
399            (T20,20) (T21,21) (T22,22) (T23,23)
400            (T24,24) (T25,25) (T26,26) (T27,27)
401            (T28,28) (T29,29) (T30,30) (T31,31)
402        );
403    };
404}
405
406#[allow(unused_macros)]
407macro_rules! with_col_sizes_64 {
408    ($callback:ident) => {
409        seq_tuples!(@from $callback
410            [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,
411             T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31]
412            [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
413             16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31];
414            (T32,32) (T33,33) (T34,34) (T35,35)
415            (T36,36) (T37,37) (T38,38) (T39,39)
416            (T40,40) (T41,41) (T42,42) (T43,43)
417            (T44,44) (T45,45) (T46,46) (T47,47)
418            (T48,48) (T49,49) (T50,50) (T51,51)
419            (T52,52) (T53,53) (T54,54) (T55,55)
420            (T56,56) (T57,57) (T58,58) (T59,59)
421            (T60,60) (T61,61) (T62,62) (T63,63)
422        );
423    };
424}
425
426#[allow(unused_macros)]
427macro_rules! with_col_sizes_128 {
428    ($callback:ident) => {
429        seq_tuples!(@from $callback
430            [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,
431             T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,
432             T32,T33,T34,T35,T36,T37,T38,T39,T40,T41,T42,T43,T44,T45,T46,T47,
433             T48,T49,T50,T51,T52,T53,T54,T55,T56,T57,T58,T59,T60,T61,T62,T63]
434            [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
435             16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
436             32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
437             48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63];
438            (T64,64) (T65,65) (T66,66) (T67,67)
439            (T68,68) (T69,69) (T70,70) (T71,71)
440            (T72,72) (T73,73) (T74,74) (T75,75)
441            (T76,76) (T77,77) (T78,78) (T79,79)
442            (T80,80) (T81,81) (T82,82) (T83,83)
443            (T84,84) (T85,85) (T86,86) (T87,87)
444            (T88,88) (T89,89) (T90,90) (T91,91)
445            (T92,92) (T93,93) (T94,94) (T95,95)
446            (T96,96) (T97,97) (T98,98) (T99,99)
447            (T100,100) (T101,101) (T102,102) (T103,103)
448            (T104,104) (T105,105) (T106,106) (T107,107)
449            (T108,108) (T109,109) (T110,110) (T111,111)
450            (T112,112) (T113,113) (T114,114) (T115,115)
451            (T116,116) (T117,117) (T118,118) (T119,119)
452            (T120,120) (T121,121) (T122,122) (T123,123)
453            (T124,124) (T125,125) (T126,126) (T127,127)
454        );
455    };
456}
457
458#[allow(unused_macros)]
459macro_rules! with_col_sizes_200 {
460    ($callback:ident) => {
461        seq_tuples!(@from $callback
462            [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,
463             T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,
464             T32,T33,T34,T35,T36,T37,T38,T39,T40,T41,T42,T43,T44,T45,T46,T47,
465             T48,T49,T50,T51,T52,T53,T54,T55,T56,T57,T58,T59,T60,T61,T62,T63,
466             T64,T65,T66,T67,T68,T69,T70,T71,T72,T73,T74,T75,T76,T77,T78,T79,
467             T80,T81,T82,T83,T84,T85,T86,T87,T88,T89,T90,T91,T92,T93,T94,T95,
468             T96,T97,T98,T99,T100,T101,T102,T103,T104,T105,T106,T107,T108,T109,T110,T111,
469             T112,T113,T114,T115,T116,T117,T118,T119,T120,T121,T122,T123,T124,T125,T126,T127]
470            [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
471             16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
472             32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
473             48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
474             64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
475             80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
476             96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
477             112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127];
478            (T128,128) (T129,129) (T130,130) (T131,131)
479            (T132,132) (T133,133) (T134,134) (T135,135)
480            (T136,136) (T137,137) (T138,138) (T139,139)
481            (T140,140) (T141,141) (T142,142) (T143,143)
482            (T144,144) (T145,145) (T146,146) (T147,147)
483            (T148,148) (T149,149) (T150,150) (T151,151)
484            (T152,152) (T153,153) (T154,154) (T155,155)
485            (T156,156) (T157,157) (T158,158) (T159,159)
486            (T160,160) (T161,161) (T162,162) (T163,163)
487            (T164,164) (T165,165) (T166,166) (T167,167)
488            (T168,168) (T169,169) (T170,170) (T171,171)
489            (T172,172) (T173,173) (T174,174) (T175,175)
490            (T176,176) (T177,177) (T178,178) (T179,179)
491            (T180,180) (T181,181) (T182,182) (T183,183)
492            (T184,184) (T185,185) (T186,186) (T187,187)
493            (T188,188) (T189,189) (T190,190) (T191,191)
494            (T192,192) (T193,193) (T194,194) (T195,195)
495            (T196,196) (T197,197) (T198,198) (T199,199)
496        );
497    };
498}
499
500macro_rules! impl_tuple_datatype {
501    ($($T:ident),+; $($idx:tt),+) => {
502        impl<$($T: DataType),+> private::Sealed for ($($T,)+) {}
503        impl<$($T: DataType),+> DataType for ($($T,)+) {}
504    };
505}
506
507with_col_sizes_8!(impl_tuple_datatype);
508
509#[cfg(any(
510    feature = "col16",
511    feature = "col32",
512    feature = "col64",
513    feature = "col128",
514    feature = "col200"
515))]
516with_col_sizes_16!(impl_tuple_datatype);
517
518#[cfg(any(
519    feature = "col32",
520    feature = "col64",
521    feature = "col128",
522    feature = "col200"
523))]
524with_col_sizes_32!(impl_tuple_datatype);
525
526#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
527with_col_sizes_64!(impl_tuple_datatype);
528
529#[cfg(any(feature = "col128", feature = "col200"))]
530with_col_sizes_128!(impl_tuple_datatype);
531
532#[cfg(feature = "col200")]
533with_col_sizes_200!(impl_tuple_datatype);
534
535#[cfg(test)]
536mod tests {
537    use super::*;
538
539    fn assert_data_type<T: DataType>() {}
540    fn assert_integral<T: Integral>() {}
541    fn assert_floating<T: Floating>() {}
542    fn assert_textual<T: Textual>() {}
543    fn assert_binary<T: Binary>() {}
544    fn assert_temporal<T: Temporal>() {}
545    fn assert_boolean_like<T: BooleanLike>() {}
546
547    #[test]
548    fn mysql_markers_have_their_expected_type_capabilities() {
549        assert_data_type::<crate::mysql::types::Any>();
550        assert_integral::<crate::mysql::types::IntUnsigned>();
551        assert_integral::<crate::mysql::types::Year>();
552        assert_floating::<crate::mysql::types::Float>();
553        assert_floating::<crate::mysql::types::Double>();
554        assert_textual::<crate::mysql::types::Enum>();
555        assert_textual::<crate::mysql::types::Set>();
556        assert_binary::<crate::mysql::types::Varbinary>();
557        assert_binary::<crate::mysql::types::Bit>();
558        assert_temporal::<crate::mysql::types::DateTime>();
559        assert_boolean_like::<crate::mysql::types::Boolean>();
560    }
561}