Skip to main content

drizzle_core/
bind.rs

1use crate::dialect::{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/// Only referenced under `arrayvec` / `smallvec-types` feature gates, so the
63/// macro definition itself is cfg-gated to match — no broad `#[allow(unused_macros)]`.
64#[cfg(any(feature = "arrayvec", feature = "smallvec-types"))]
65macro_rules! impl_value_type_const_n {
66    ($dialect:ty, $sql:ty => $($ty:ty),+ $(,)?) => {
67        $(
68            impl<const N: usize> ValueTypeForDialect<$dialect> for $ty {
69                type SQLType = $sql;
70            }
71        )+
72    };
73}
74
75// =============================================================================
76// SQLite mappings
77// =============================================================================
78
79use drizzle_types::sqlite::types as sqlite_ty;
80
81impl_value_type!(SQLiteDialect, sqlite_ty::Integer =>
82    i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, bool);
83
84impl_value_type!(SQLiteDialect, sqlite_ty::Real => f32, f64);
85
86impl_value_type!(SQLiteDialect, sqlite_ty::Text => &str);
87
88#[cfg(any(feature = "alloc", feature = "std"))]
89impl_value_type!(SQLiteDialect, sqlite_ty::Text =>
90    Cow<'_, str>,
91    String,
92    Box<String>,
93    Rc<String>,
94    Arc<String>,
95    Box<str>,
96    Rc<str>,
97    Arc<str>,
98);
99
100impl_value_type!(SQLiteDialect, sqlite_ty::Text => compact_str::CompactString);
101
102#[cfg(feature = "arrayvec")]
103impl_value_type_const_n!(SQLiteDialect, sqlite_ty::Text => arrayvec::ArrayString<N>);
104
105impl_value_type!(SQLiteDialect, sqlite_ty::Blob => &[u8]);
106
107#[cfg(any(feature = "alloc", feature = "std"))]
108impl_value_type!(SQLiteDialect, sqlite_ty::Blob =>
109    Cow<'_, [u8]>,
110    Vec<u8>,
111    Box<Vec<u8>>,
112    Rc<Vec<u8>>,
113    Arc<Vec<u8>>,
114);
115
116#[cfg(feature = "arrayvec")]
117impl_value_type_const_n!(SQLiteDialect, sqlite_ty::Blob => arrayvec::ArrayVec<u8, N>);
118
119#[cfg(feature = "bytes")]
120impl_value_type!(SQLiteDialect, sqlite_ty::Blob => bytes::Bytes, bytes::BytesMut);
121
122#[cfg(feature = "smallvec-types")]
123impl_value_type_const_n!(SQLiteDialect, sqlite_ty::Blob => smallvec::SmallVec<[u8; N]>);
124
125#[cfg(feature = "uuid")]
126impl_value_type!(SQLiteDialect, sqlite_ty::Blob => uuid::Uuid, &uuid::Uuid);
127
128#[cfg(feature = "chrono")]
129impl_value_type!(SQLiteDialect, sqlite_ty::Text =>
130    chrono::NaiveDate,
131    chrono::NaiveTime,
132    chrono::NaiveDateTime,
133    chrono::DateTime<chrono::FixedOffset>,
134    chrono::DateTime<chrono::Utc>,
135    chrono::Duration,
136);
137
138#[cfg(feature = "time")]
139impl_value_type!(SQLiteDialect, sqlite_ty::Text =>
140    time::Date,
141    time::Time,
142    time::PrimitiveDateTime,
143    time::OffsetDateTime,
144    time::Duration,
145);
146
147#[cfg(feature = "rust-decimal")]
148impl_value_type!(SQLiteDialect, sqlite_ty::Text =>
149    rust_decimal::Decimal,
150    &rust_decimal::Decimal,
151);
152
153#[cfg(feature = "serde")]
154impl_value_type!(SQLiteDialect, sqlite_ty::Text => serde_json::Value);
155
156// =============================================================================
157// Postgres mappings
158// =============================================================================
159
160use drizzle_types::postgres::types as pg_ty;
161
162impl_value_type!(PostgresDialect, pg_ty::Int2 => i8, i16, u8);
163impl_value_type!(PostgresDialect, pg_ty::Int4 => i32, u16);
164impl_value_type!(PostgresDialect, pg_ty::Int8 => i64, u32, u64, isize, usize);
165impl_value_type!(PostgresDialect, pg_ty::Float4 => f32);
166impl_value_type!(PostgresDialect, pg_ty::Float8 => f64);
167impl_value_type!(PostgresDialect, pg_ty::Boolean => bool);
168
169impl_value_type!(PostgresDialect, pg_ty::Text => &str);
170
171#[cfg(any(feature = "alloc", feature = "std"))]
172impl_value_type!(PostgresDialect, pg_ty::Text =>
173    Cow<'_, str>,
174    String,
175    Box<String>,
176    Rc<String>,
177    Arc<String>,
178    Box<str>,
179    Rc<str>,
180    Arc<str>,
181);
182
183#[cfg(feature = "compact-str")]
184impl_value_type!(PostgresDialect, pg_ty::Text => compact_str::CompactString);
185
186#[cfg(feature = "arrayvec")]
187impl_value_type_const_n!(PostgresDialect, pg_ty::Text => arrayvec::ArrayString<N>);
188
189impl_value_type!(PostgresDialect, pg_ty::Bytea => &[u8]);
190
191#[cfg(any(feature = "alloc", feature = "std"))]
192impl_value_type!(PostgresDialect, pg_ty::Bytea =>
193    Cow<'_, [u8]>,
194    Vec<u8>,
195    Box<Vec<u8>>,
196    Rc<Vec<u8>>,
197    Arc<Vec<u8>>,
198);
199
200#[cfg(feature = "arrayvec")]
201impl_value_type_const_n!(PostgresDialect, pg_ty::Bytea => arrayvec::ArrayVec<u8, N>);
202
203#[cfg(feature = "bytes")]
204impl_value_type!(PostgresDialect, pg_ty::Bytea => bytes::Bytes, bytes::BytesMut);
205
206#[cfg(feature = "smallvec-types")]
207impl_value_type_const_n!(PostgresDialect, pg_ty::Bytea => smallvec::SmallVec<[u8; N]>);
208
209#[cfg(feature = "uuid")]
210impl_value_type!(PostgresDialect, pg_ty::Uuid => uuid::Uuid, &uuid::Uuid);
211
212#[cfg(feature = "rust-decimal")]
213impl_value_type!(PostgresDialect, pg_ty::Numeric =>
214    rust_decimal::Decimal,
215    &rust_decimal::Decimal,
216);
217
218#[cfg(feature = "serde")]
219impl_value_type!(PostgresDialect, pg_ty::Json => serde_json::Value);
220
221#[cfg(feature = "chrono")]
222impl_value_type!(PostgresDialect, pg_ty::Date => chrono::NaiveDate);
223#[cfg(feature = "chrono")]
224impl_value_type!(PostgresDialect, pg_ty::Time => chrono::NaiveTime);
225#[cfg(feature = "chrono")]
226impl_value_type!(PostgresDialect, pg_ty::Timestamp => chrono::NaiveDateTime);
227#[cfg(feature = "chrono")]
228impl_value_type!(PostgresDialect, pg_ty::Timestamptz =>
229    chrono::DateTime<chrono::FixedOffset>,
230    chrono::DateTime<chrono::Utc>,
231);
232#[cfg(feature = "chrono")]
233impl_value_type!(PostgresDialect, pg_ty::Interval => chrono::Duration);
234
235#[cfg(feature = "time")]
236impl_value_type!(PostgresDialect, pg_ty::Date => time::Date);
237#[cfg(feature = "time")]
238impl_value_type!(PostgresDialect, pg_ty::Time => time::Time);
239#[cfg(feature = "time")]
240impl_value_type!(PostgresDialect, pg_ty::Timestamp => time::PrimitiveDateTime);
241#[cfg(feature = "time")]
242impl_value_type!(PostgresDialect, pg_ty::Timestamptz => time::OffsetDateTime);
243#[cfg(feature = "time")]
244impl_value_type!(PostgresDialect, pg_ty::Interval => time::Duration);
245
246#[cfg(feature = "cidr")]
247impl_value_type!(PostgresDialect, pg_ty::Inet => cidr::IpInet);
248#[cfg(feature = "cidr")]
249impl_value_type!(PostgresDialect, pg_ty::Cidr => cidr::IpCidr);
250#[cfg(feature = "cidr")]
251impl_value_type!(PostgresDialect, pg_ty::MacAddr => [u8; 6]);
252#[cfg(feature = "cidr")]
253impl_value_type!(PostgresDialect, pg_ty::MacAddr8 => [u8; 8]);
254
255#[cfg(feature = "geo-types")]
256impl_value_type!(PostgresDialect, pg_ty::Point => geo_types::Point<f64>);
257#[cfg(feature = "geo-types")]
258impl_value_type!(PostgresDialect, pg_ty::LineString => geo_types::LineString<f64>);
259#[cfg(feature = "geo-types")]
260impl_value_type!(PostgresDialect, pg_ty::Rect => geo_types::Rect<f64>);
261
262#[cfg(feature = "bit-vec")]
263impl_value_type!(PostgresDialect, pg_ty::BitString => bit_vec::BitVec);
264
265// Postgres Vec<T> → Array<T>
266
267#[cfg(any(feature = "alloc", feature = "std"))]
268impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Text> =>
269    Vec<String>, Vec<&str>);
270
271#[cfg(any(feature = "alloc", feature = "std"))]
272impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Int2> => Vec<i16>);
273
274#[cfg(any(feature = "alloc", feature = "std"))]
275impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Int4> => Vec<i32>);
276
277#[cfg(any(feature = "alloc", feature = "std"))]
278impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Int8> => Vec<i64>);
279
280#[cfg(any(feature = "alloc", feature = "std"))]
281impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Float4> => Vec<f32>);
282
283#[cfg(any(feature = "alloc", feature = "std"))]
284impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Float8> => Vec<f64>);
285
286#[cfg(any(feature = "alloc", feature = "std"))]
287impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Boolean> => Vec<bool>);
288
289#[cfg(all(any(feature = "alloc", feature = "std"), feature = "uuid"))]
290impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Uuid> => Vec<uuid::Uuid>);
291
292#[cfg(all(any(feature = "alloc", feature = "std"), feature = "chrono"))]
293impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Date> => Vec<chrono::NaiveDate>);
294
295#[cfg(all(any(feature = "alloc", feature = "std"), feature = "chrono"))]
296impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Time> => Vec<chrono::NaiveTime>);
297
298#[cfg(all(any(feature = "alloc", feature = "std"), feature = "chrono"))]
299impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Timestamp> => Vec<chrono::NaiveDateTime>);
300
301#[cfg(all(any(feature = "alloc", feature = "std"), feature = "chrono"))]
302impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Timestamptz> => Vec<chrono::DateTime<chrono::Utc>>);
303
304#[cfg(all(any(feature = "alloc", feature = "std"), feature = "rust-decimal"))]
305impl_value_type!(PostgresDialect, drizzle_types::Array<pg_ty::Numeric> => Vec<rust_decimal::Decimal>);