Skip to main content

drizzle_core/
bind.rs

1use crate::dialect::{MySQLDialect, PostgresDialect, SQLiteDialect};
2use crate::traits::SQLParam;
3use crate::types::{Assignable, DataType};
4
5#[cfg(any(feature = "alloc", feature = "std"))]
6use crate::prelude::{Arc, Box, Cow, Rc, String, Vec};
7
8/// Maps a Rust value type to its SQL marker for a specific dialect.
9pub trait ValueTypeForDialect<D> {
10    type SQLType: DataType;
11}
12
13/// Converts a Rust value into a dialect value while checking SQL marker assignment.
14pub trait BindValue<'a, V: SQLParam, Expected: DataType>: Sized {
15    fn into_bind_value(self) -> V;
16}
17
18/// Converts an optional Rust value into a nullable dialect value.
19pub trait NullableBindValue<'a, V: SQLParam, Expected: DataType>: Sized {
20    fn into_nullable_bind_value(self) -> V;
21}
22
23impl<V, Expected, T> BindValue<'_, V, Expected> for T
24where
25    V: SQLParam + From<T>,
26    Expected: DataType + Assignable<<T as ValueTypeForDialect<V::DialectMarker>>::SQLType>,
27    T: ValueTypeForDialect<V::DialectMarker>,
28{
29    fn into_bind_value(self) -> V {
30        V::from(self)
31    }
32}
33
34impl<V, Expected, T> NullableBindValue<'_, V, Expected> for Option<T>
35where
36    V: SQLParam + From<Self>,
37    Expected: DataType + Assignable<<T as ValueTypeForDialect<V::DialectMarker>>::SQLType>,
38    T: ValueTypeForDialect<V::DialectMarker>,
39{
40    fn into_nullable_bind_value(self) -> V {
41        V::from(self)
42    }
43}
44
45// =============================================================================
46// ValueTypeForDialect impl generator
47// =============================================================================
48
49/// Declare `ValueTypeForDialect<$dialect>::SQLType = $sql` for one or more types.
50macro_rules! impl_value_type {
51    ($dialect:ty, $sql:ty => $($ty:ty),+ $(,)?) => {
52        $(
53            impl ValueTypeForDialect<$dialect> for $ty {
54                type SQLType = $sql;
55            }
56        )+
57    };
58}
59
60/// Same as `impl_value_type!`, but for types generic over `const N: usize`.
61///
62/// Used by optional containers and by fixed-size arrays supported by MySQL.
63macro_rules! impl_value_type_const_n {
64    ($dialect:ty, $sql:ty => $($ty:ty),+ $(,)?) => {
65        $(
66            impl<const N: usize> ValueTypeForDialect<$dialect> for $ty {
67                type SQLType = $sql;
68            }
69        )+
70    };
71}
72
73// =============================================================================
74// SQLite mappings
75// =============================================================================
76
77use drizzle_types::sqlite::types as sqlite_ty;
78
79impl_value_type!(SQLiteDialect, sqlite_ty::Integer =>
80    i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, bool);
81
82impl_value_type!(SQLiteDialect, sqlite_ty::Real => f32, f64);
83
84impl_value_type!(SQLiteDialect, sqlite_ty::Text => &str);
85
86#[cfg(any(feature = "alloc", feature = "std"))]
87impl_value_type!(SQLiteDialect, sqlite_ty::Text =>
88    Cow<'_, str>,
89    String,
90    Box<String>,
91    Rc<String>,
92    Arc<String>,
93    Box<str>,
94    Rc<str>,
95    Arc<str>,
96);
97
98impl_value_type!(SQLiteDialect, sqlite_ty::Text => compact_str::CompactString);
99
100#[cfg(feature = "arrayvec")]
101impl_value_type_const_n!(SQLiteDialect, sqlite_ty::Text => arrayvec::ArrayString<N>);
102
103impl_value_type!(SQLiteDialect, sqlite_ty::Blob => &[u8]);
104
105#[cfg(any(feature = "alloc", feature = "std"))]
106impl_value_type!(SQLiteDialect, sqlite_ty::Blob =>
107    Cow<'_, [u8]>,
108    Vec<u8>,
109    Box<Vec<u8>>,
110    Rc<Vec<u8>>,
111    Arc<Vec<u8>>,
112);
113
114#[cfg(feature = "arrayvec")]
115impl_value_type_const_n!(SQLiteDialect, sqlite_ty::Blob => arrayvec::ArrayVec<u8, N>);
116
117#[cfg(feature = "bytes")]
118impl_value_type!(SQLiteDialect, sqlite_ty::Blob => bytes::Bytes, bytes::BytesMut);
119
120#[cfg(feature = "smallvec-types")]
121impl_value_type_const_n!(SQLiteDialect, sqlite_ty::Blob => smallvec::SmallVec<[u8; N]>);
122
123#[cfg(feature = "uuid")]
124impl_value_type!(SQLiteDialect, sqlite_ty::Blob => uuid::Uuid, &uuid::Uuid);
125
126#[cfg(feature = "chrono")]
127impl_value_type!(SQLiteDialect, sqlite_ty::Text =>
128    chrono::NaiveDate,
129    chrono::NaiveTime,
130    chrono::NaiveDateTime,
131    chrono::DateTime<chrono::FixedOffset>,
132    chrono::DateTime<chrono::Utc>,
133    chrono::Duration,
134);
135
136#[cfg(feature = "time")]
137impl_value_type!(SQLiteDialect, sqlite_ty::Text =>
138    time::Date,
139    time::Time,
140    time::PrimitiveDateTime,
141    time::OffsetDateTime,
142    time::Duration,
143);
144
145#[cfg(feature = "jiff")]
146impl_value_type!(SQLiteDialect, sqlite_ty::Text =>
147    jiff::civil::Date,
148    jiff::civil::Time,
149    jiff::civil::DateTime,
150    jiff::Timestamp,
151);
152
153#[cfg(feature = "rust-decimal")]
154impl_value_type!(SQLiteDialect, sqlite_ty::Text =>
155    rust_decimal::Decimal,
156    &rust_decimal::Decimal,
157);
158
159#[cfg(feature = "serde")]
160impl_value_type!(SQLiteDialect, sqlite_ty::Text => serde_json::Value);
161
162// =============================================================================
163// Postgres mappings
164// =============================================================================
165
166use drizzle_types::postgres::types as pg_ty;
167
168impl_value_type!(PostgresDialect, pg_ty::Int2 => i8, i16, u8);
169impl_value_type!(PostgresDialect, pg_ty::Int4 => i32, u16);
170impl_value_type!(PostgresDialect, pg_ty::Int8 => i64, u32, u64, isize, usize);
171impl_value_type!(PostgresDialect, pg_ty::Float4 => f32);
172impl_value_type!(PostgresDialect, pg_ty::Float8 => f64);
173impl_value_type!(PostgresDialect, pg_ty::Boolean => bool);
174
175impl_value_type!(PostgresDialect, pg_ty::Text => &str);
176
177#[cfg(any(feature = "alloc", feature = "std"))]
178impl_value_type!(PostgresDialect, pg_ty::Text =>
179    Cow<'_, str>,
180    String,
181    Box<String>,
182    Rc<String>,
183    Arc<String>,
184    Box<str>,
185    Rc<str>,
186    Arc<str>,
187);
188
189#[cfg(feature = "compact-str")]
190impl_value_type!(PostgresDialect, pg_ty::Text => compact_str::CompactString);
191
192#[cfg(feature = "arrayvec")]
193impl_value_type_const_n!(PostgresDialect, pg_ty::Text => arrayvec::ArrayString<N>);
194
195impl_value_type!(PostgresDialect, pg_ty::Bytea => &[u8]);
196
197#[cfg(any(feature = "alloc", feature = "std"))]
198impl_value_type!(PostgresDialect, pg_ty::Bytea =>
199    Cow<'_, [u8]>,
200    Vec<u8>,
201    Box<Vec<u8>>,
202    Rc<Vec<u8>>,
203    Arc<Vec<u8>>,
204);
205
206#[cfg(feature = "arrayvec")]
207impl_value_type_const_n!(PostgresDialect, pg_ty::Bytea => arrayvec::ArrayVec<u8, N>);
208
209#[cfg(feature = "bytes")]
210impl_value_type!(PostgresDialect, pg_ty::Bytea => bytes::Bytes, bytes::BytesMut);
211
212#[cfg(feature = "smallvec-types")]
213impl_value_type_const_n!(PostgresDialect, pg_ty::Bytea => smallvec::SmallVec<[u8; N]>);
214
215#[cfg(feature = "uuid")]
216impl_value_type!(PostgresDialect, pg_ty::Uuid => uuid::Uuid, &uuid::Uuid);
217
218#[cfg(feature = "rust-decimal")]
219impl_value_type!(PostgresDialect, pg_ty::Numeric =>
220    rust_decimal::Decimal,
221    &rust_decimal::Decimal,
222);
223
224#[cfg(feature = "serde")]
225impl_value_type!(PostgresDialect, pg_ty::Json => serde_json::Value);
226
227#[cfg(feature = "chrono")]
228impl_value_type!(PostgresDialect, pg_ty::Date => chrono::NaiveDate);
229#[cfg(feature = "chrono")]
230impl_value_type!(PostgresDialect, pg_ty::Time => chrono::NaiveTime);
231#[cfg(feature = "chrono")]
232impl_value_type!(PostgresDialect, pg_ty::Timestamp => chrono::NaiveDateTime);
233#[cfg(feature = "chrono")]
234impl_value_type!(PostgresDialect, pg_ty::Timestamptz =>
235    chrono::DateTime<chrono::FixedOffset>,
236    chrono::DateTime<chrono::Utc>,
237);
238#[cfg(feature = "chrono")]
239impl_value_type!(PostgresDialect, pg_ty::Interval => chrono::Duration);
240
241#[cfg(feature = "time")]
242impl_value_type!(PostgresDialect, pg_ty::Date => time::Date);
243#[cfg(feature = "time")]
244impl_value_type!(PostgresDialect, pg_ty::Time => time::Time);
245#[cfg(feature = "time")]
246impl_value_type!(PostgresDialect, pg_ty::Timestamp => time::PrimitiveDateTime);
247#[cfg(feature = "time")]
248impl_value_type!(PostgresDialect, pg_ty::Timestamptz => time::OffsetDateTime);
249#[cfg(feature = "time")]
250impl_value_type!(PostgresDialect, pg_ty::Interval => time::Duration);
251
252#[cfg(feature = "jiff")]
253impl_value_type!(PostgresDialect, pg_ty::Date => jiff::civil::Date);
254#[cfg(feature = "jiff")]
255impl_value_type!(PostgresDialect, pg_ty::Time => jiff::civil::Time);
256#[cfg(feature = "jiff")]
257impl_value_type!(PostgresDialect, pg_ty::Timestamp => jiff::civil::DateTime);
258#[cfg(feature = "jiff")]
259impl_value_type!(PostgresDialect, pg_ty::Timestamptz => jiff::Timestamp);
260
261#[cfg(feature = "cidr")]
262impl_value_type!(PostgresDialect, pg_ty::Inet => cidr::IpInet);
263#[cfg(feature = "cidr")]
264impl_value_type!(PostgresDialect, pg_ty::Cidr => cidr::IpCidr);
265#[cfg(feature = "cidr")]
266impl_value_type!(PostgresDialect, pg_ty::MacAddr => [u8; 6]);
267#[cfg(feature = "cidr")]
268impl_value_type!(PostgresDialect, pg_ty::MacAddr8 => [u8; 8]);
269
270#[cfg(feature = "geo-types")]
271impl_value_type!(PostgresDialect, pg_ty::Point => geo_types::Point<f64>);
272#[cfg(feature = "geo-types")]
273impl_value_type!(PostgresDialect, pg_ty::LineString => geo_types::LineString<f64>);
274#[cfg(feature = "geo-types")]
275impl_value_type!(PostgresDialect, pg_ty::Rect => geo_types::Rect<f64>);
276
277#[cfg(feature = "bit-vec")]
278impl_value_type!(PostgresDialect, pg_ty::BitString => bit_vec::BitVec);
279
280// Postgres Vec<T> → Array<T>
281
282#[cfg(any(feature = "alloc", feature = "std"))]
283impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Text> =>
284    Vec<String>, Vec<&str>);
285
286#[cfg(any(feature = "alloc", feature = "std"))]
287impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Int2> => Vec<i16>);
288
289#[cfg(any(feature = "alloc", feature = "std"))]
290impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Int4> => Vec<i32>);
291
292#[cfg(any(feature = "alloc", feature = "std"))]
293impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Int8> => Vec<i64>);
294
295#[cfg(any(feature = "alloc", feature = "std"))]
296impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Float4> => Vec<f32>);
297
298#[cfg(any(feature = "alloc", feature = "std"))]
299impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Float8> => Vec<f64>);
300
301#[cfg(any(feature = "alloc", feature = "std"))]
302impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Boolean> => Vec<bool>);
303
304#[cfg(all(any(feature = "alloc", feature = "std"), feature = "uuid"))]
305impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Uuid> => Vec<uuid::Uuid>);
306
307#[cfg(all(any(feature = "alloc", feature = "std"), feature = "chrono"))]
308impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Date> => Vec<chrono::NaiveDate>);
309
310#[cfg(all(any(feature = "alloc", feature = "std"), feature = "chrono"))]
311impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Time> => Vec<chrono::NaiveTime>);
312
313#[cfg(all(any(feature = "alloc", feature = "std"), feature = "chrono"))]
314impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Timestamp> => Vec<chrono::NaiveDateTime>);
315
316#[cfg(all(any(feature = "alloc", feature = "std"), feature = "chrono"))]
317impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Timestamptz> => Vec<chrono::DateTime<chrono::Utc>>);
318
319#[cfg(all(any(feature = "alloc", feature = "std"), feature = "rust-decimal"))]
320impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Numeric> => Vec<rust_decimal::Decimal>);
321
322// =============================================================================
323// MySQL mappings
324// =============================================================================
325
326use drizzle_types::mysql::types as mysql_ty;
327
328impl_value_type!(MySQLDialect, mysql_ty::TinyInt => i8);
329impl_value_type!(MySQLDialect, mysql_ty::SmallInt => i16);
330impl_value_type!(MySQLDialect, mysql_ty::Int => i32);
331impl_value_type!(MySQLDialect, mysql_ty::BigInt => i64, isize);
332impl_value_type!(MySQLDialect, mysql_ty::TinyIntUnsigned => u8);
333impl_value_type!(MySQLDialect, mysql_ty::SmallIntUnsigned => u16);
334impl_value_type!(MySQLDialect, mysql_ty::IntUnsigned => u32);
335impl_value_type!(MySQLDialect, mysql_ty::BigIntUnsigned => u64, usize);
336impl_value_type!(MySQLDialect, mysql_ty::Float => f32);
337impl_value_type!(MySQLDialect, mysql_ty::Double => f64);
338impl_value_type!(MySQLDialect, mysql_ty::Boolean => bool);
339
340impl_value_type!(MySQLDialect, mysql_ty::Text => &str);
341
342#[cfg(any(feature = "alloc", feature = "std"))]
343impl_value_type!(MySQLDialect, mysql_ty::Text =>
344    Cow<'_, str>,
345    String,
346    Box<String>,
347    Rc<String>,
348    Arc<String>,
349    Box<str>,
350    Rc<str>,
351    Arc<str>,
352);
353
354#[cfg(feature = "compact-str")]
355impl_value_type!(MySQLDialect, mysql_ty::Text => compact_str::CompactString);
356
357#[cfg(feature = "arrayvec")]
358impl_value_type_const_n!(MySQLDialect, mysql_ty::Varchar => arrayvec::ArrayString<N>);
359
360impl_value_type!(MySQLDialect, mysql_ty::Blob => &[u8]);
361
362#[cfg(any(feature = "alloc", feature = "std"))]
363impl_value_type!(MySQLDialect, mysql_ty::Blob =>
364    Cow<'_, [u8]>,
365    Vec<u8>,
366    Box<Vec<u8>>,
367    Rc<Vec<u8>>,
368    Arc<Vec<u8>>,
369);
370
371#[cfg(feature = "arrayvec")]
372impl_value_type_const_n!(MySQLDialect, mysql_ty::Varbinary => arrayvec::ArrayVec<u8, N>);
373
374impl_value_type_const_n!(MySQLDialect, mysql_ty::Binary => [u8; N]);
375impl_value_type_const_n!(MySQLDialect, mysql_ty::Char => [char; N]);
376
377#[cfg(feature = "bytes")]
378impl_value_type!(MySQLDialect, mysql_ty::Blob => bytes::Bytes, bytes::BytesMut);
379
380#[cfg(feature = "smallvec-types")]
381impl_value_type_const_n!(MySQLDialect, mysql_ty::Blob => smallvec::SmallVec<[u8; N]>);
382
383#[cfg(feature = "uuid")]
384impl_value_type!(MySQLDialect, mysql_ty::Binary => uuid::Uuid, &uuid::Uuid);
385
386#[cfg(feature = "rust-decimal")]
387impl_value_type!(MySQLDialect, mysql_ty::Decimal =>
388    rust_decimal::Decimal,
389    &rust_decimal::Decimal,
390);
391
392#[cfg(feature = "serde")]
393impl_value_type!(MySQLDialect, mysql_ty::Json => serde_json::Value);
394
395#[cfg(feature = "chrono")]
396impl_value_type!(MySQLDialect, mysql_ty::Date => chrono::NaiveDate);
397#[cfg(feature = "chrono")]
398impl_value_type!(MySQLDialect, mysql_ty::Time => chrono::NaiveTime);
399#[cfg(feature = "chrono")]
400impl_value_type!(MySQLDialect, mysql_ty::DateTime => chrono::NaiveDateTime);
401#[cfg(feature = "chrono")]
402impl_value_type!(MySQLDialect, mysql_ty::Timestamp =>
403    chrono::DateTime<chrono::FixedOffset>,
404    chrono::DateTime<chrono::Utc>,
405);
406
407#[cfg(feature = "time")]
408impl_value_type!(MySQLDialect, mysql_ty::Date => time::Date);
409#[cfg(feature = "time")]
410impl_value_type!(MySQLDialect, mysql_ty::Time => time::Time);
411#[cfg(feature = "time")]
412impl_value_type!(MySQLDialect, mysql_ty::DateTime => time::PrimitiveDateTime);
413#[cfg(feature = "time")]
414impl_value_type!(MySQLDialect, mysql_ty::Timestamp => time::OffsetDateTime);
415
416#[cfg(feature = "jiff")]
417impl_value_type!(MySQLDialect, mysql_ty::Date => jiff::civil::Date);
418#[cfg(feature = "jiff")]
419impl_value_type!(MySQLDialect, mysql_ty::Time => jiff::civil::Time);
420#[cfg(feature = "jiff")]
421impl_value_type!(MySQLDialect, mysql_ty::DateTime => jiff::civil::DateTime);
422#[cfg(feature = "jiff")]
423impl_value_type!(MySQLDialect, mysql_ty::Timestamp => jiff::Timestamp);