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