Skip to main content

drizzle_core/expr/
primitives.rs

1//! Expr implementations for Rust primitive types.
2//!
3//! These implementations allow using Rust literals directly in type-safe
4//! SQL expressions.
5
6use crate::bind::ValueTypeForDialect;
7use crate::dialect::DialectTypes;
8use crate::prelude::*;
9use crate::sql::SQL;
10use crate::traits::{SQLBytes, SQLParam};
11
12use super::{Expr, NonNull, Null, Nullability, Scalar};
13
14// =============================================================================
15// Integer Types
16// =============================================================================
17
18impl<'a, V> Expr<'a, V> for i8
19where
20    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
21    Self: ValueTypeForDialect<V::DialectMarker>,
22{
23    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
24    type Nullable = NonNull;
25    type Aggregate = Scalar;
26}
27
28impl<'a, V> Expr<'a, V> for i16
29where
30    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
31    Self: ValueTypeForDialect<V::DialectMarker>,
32{
33    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
34    type Nullable = NonNull;
35    type Aggregate = Scalar;
36}
37
38impl<'a, V> Expr<'a, V> for i32
39where
40    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
41    Self: ValueTypeForDialect<V::DialectMarker>,
42{
43    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
44    type Nullable = NonNull;
45    type Aggregate = Scalar;
46}
47
48impl<'a, V> Expr<'a, V> for i64
49where
50    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
51    Self: ValueTypeForDialect<V::DialectMarker>,
52{
53    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
54    type Nullable = NonNull;
55    type Aggregate = Scalar;
56}
57
58impl<'a, V> Expr<'a, V> for isize
59where
60    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
61    Self: ValueTypeForDialect<V::DialectMarker>,
62{
63    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
64    type Nullable = NonNull;
65    type Aggregate = Scalar;
66}
67
68// =============================================================================
69// Unsigned Integer Types
70// =============================================================================
71
72impl<'a, V> Expr<'a, V> for u8
73where
74    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
75    Self: ValueTypeForDialect<V::DialectMarker>,
76{
77    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
78    type Nullable = NonNull;
79    type Aggregate = Scalar;
80}
81
82impl<'a, V> Expr<'a, V> for u16
83where
84    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
85    Self: ValueTypeForDialect<V::DialectMarker>,
86{
87    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
88    type Nullable = NonNull;
89    type Aggregate = Scalar;
90}
91
92impl<'a, V> Expr<'a, V> for u32
93where
94    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
95    Self: ValueTypeForDialect<V::DialectMarker>,
96{
97    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
98    type Nullable = NonNull;
99    type Aggregate = Scalar;
100}
101
102impl<'a, V> Expr<'a, V> for u64
103where
104    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
105    Self: ValueTypeForDialect<V::DialectMarker>,
106{
107    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
108    type Nullable = NonNull;
109    type Aggregate = Scalar;
110}
111
112impl<'a, V> Expr<'a, V> for usize
113where
114    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
115    Self: ValueTypeForDialect<V::DialectMarker>,
116{
117    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
118    type Nullable = NonNull;
119    type Aggregate = Scalar;
120}
121
122// =============================================================================
123// Floating-Point Types
124// =============================================================================
125
126impl<'a, V> Expr<'a, V> for f32
127where
128    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
129    Self: ValueTypeForDialect<V::DialectMarker>,
130{
131    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
132    type Nullable = NonNull;
133    type Aggregate = Scalar;
134}
135
136impl<'a, V> Expr<'a, V> for f64
137where
138    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
139    Self: ValueTypeForDialect<V::DialectMarker>,
140{
141    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
142    type Nullable = NonNull;
143    type Aggregate = Scalar;
144}
145
146// =============================================================================
147// Boolean Type
148// =============================================================================
149
150impl<'a, V> Expr<'a, V> for bool
151where
152    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
153    Self: ValueTypeForDialect<V::DialectMarker>,
154{
155    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
156    type Nullable = NonNull;
157    type Aggregate = Scalar;
158}
159
160// =============================================================================
161// String Types
162// =============================================================================
163
164impl<'a, V> Expr<'a, V> for &'a str
165where
166    V: SQLParam + 'a + From<&'a str> + Into<Cow<'a, V>>,
167    Self: ValueTypeForDialect<V::DialectMarker>,
168{
169    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
170    type Nullable = NonNull;
171    type Aggregate = Scalar;
172}
173
174impl<'a, V> Expr<'a, V> for String
175where
176    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
177    Self: ValueTypeForDialect<V::DialectMarker>,
178{
179    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
180    type Nullable = NonNull;
181    type Aggregate = Scalar;
182}
183
184#[cfg(feature = "compact-str")]
185impl<'a, V> Expr<'a, V> for compact_str::CompactString
186where
187    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
188    Self: ValueTypeForDialect<V::DialectMarker>,
189{
190    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
191    type Nullable = NonNull;
192    type Aggregate = Scalar;
193}
194
195#[cfg(feature = "bytes")]
196impl<'a, V> Expr<'a, V> for bytes::Bytes
197where
198    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
199    Self: ValueTypeForDialect<V::DialectMarker>,
200{
201    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
202    type Nullable = NonNull;
203    type Aggregate = Scalar;
204}
205
206#[cfg(feature = "bytes")]
207impl<'a, V> Expr<'a, V> for bytes::BytesMut
208where
209    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
210    Self: ValueTypeForDialect<V::DialectMarker>,
211{
212    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
213    type Nullable = NonNull;
214    type Aggregate = Scalar;
215}
216
217#[cfg(feature = "arrayvec")]
218impl<'a, V, const N: usize> Expr<'a, V> for arrayvec::ArrayString<N>
219where
220    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
221    Self: ValueTypeForDialect<V::DialectMarker>,
222{
223    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
224    type Nullable = NonNull;
225    type Aggregate = Scalar;
226}
227
228#[cfg(feature = "arrayvec")]
229impl<'a, V, const N: usize> Expr<'a, V> for arrayvec::ArrayVec<u8, N>
230where
231    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
232    Self: ValueTypeForDialect<V::DialectMarker>,
233{
234    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
235    type Nullable = NonNull;
236    type Aggregate = Scalar;
237}
238
239#[cfg(feature = "smallvec-types")]
240impl<'a, V, const N: usize> Expr<'a, V> for smallvec::SmallVec<[u8; N]>
241where
242    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
243    Self: ValueTypeForDialect<V::DialectMarker>,
244{
245    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
246    type Nullable = NonNull;
247    type Aggregate = Scalar;
248}
249
250impl<'a, V, const N: usize> Expr<'a, V> for [char; N]
251where
252    V: SQLParam + 'a + From<Self> + From<char> + Into<Cow<'a, V>>,
253    Self: ValueTypeForDialect<V::DialectMarker>,
254{
255    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
256    type Nullable = NonNull;
257    type Aggregate = Scalar;
258
259    fn to_expr_sql(&self) -> SQL<'a, V> {
260        SQL::param(V::from(*self))
261    }
262
263    fn into_expr_sql(self) -> SQL<'a, V> {
264        SQL::param(V::from(self))
265    }
266}
267
268// =============================================================================
269// Binary Types
270// =============================================================================
271
272impl<'a, V> Expr<'a, V> for &'a [u8]
273where
274    V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + From<u8> + Into<Cow<'a, V>>,
275{
276    type SQLType = <V::DialectMarker as DialectTypes>::Bytes;
277    type Nullable = NonNull;
278    type Aggregate = Scalar;
279
280    fn to_expr_sql(&self) -> SQL<'a, V> {
281        SQL::bytes(*self)
282    }
283
284    fn into_expr_sql(self) -> SQL<'a, V> {
285        SQL::bytes(self)
286    }
287}
288
289impl<'a, V, const N: usize> Expr<'a, V> for [u8; N]
290where
291    V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + From<u8> + Into<Cow<'a, V>>,
292{
293    type SQLType = <V::DialectMarker as DialectTypes>::Bytes;
294    type Nullable = NonNull;
295    type Aggregate = Scalar;
296
297    fn to_expr_sql(&self) -> SQL<'a, V> {
298        SQL::bytes(self.to_vec())
299    }
300
301    fn into_expr_sql(self) -> SQL<'a, V> {
302        SQL::bytes(self.to_vec())
303    }
304}
305
306impl<'a, V> Expr<'a, V> for Vec<u8>
307where
308    V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + From<u8> + Into<Cow<'a, V>>,
309{
310    type SQLType = <V::DialectMarker as DialectTypes>::Bytes;
311    type Nullable = NonNull;
312    type Aggregate = Scalar;
313
314    fn to_expr_sql(&self) -> SQL<'a, V> {
315        SQL::bytes(self.clone())
316    }
317
318    fn into_expr_sql(self) -> SQL<'a, V> {
319        SQL::bytes(self)
320    }
321}
322
323impl<'a, V> Expr<'a, V> for Cow<'a, [u8]>
324where
325    V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + Into<Cow<'a, V>>,
326{
327    type SQLType = <V::DialectMarker as DialectTypes>::Bytes;
328    type Nullable = NonNull;
329    type Aggregate = Scalar;
330
331    fn to_expr_sql(&self) -> SQL<'a, V> {
332        match self {
333            Cow::Borrowed(value) => SQL::bytes(*value),
334            Cow::Owned(value) => SQL::bytes(value.clone()),
335        }
336    }
337
338    fn into_expr_sql(self) -> SQL<'a, V> {
339        SQL::bytes(self)
340    }
341}
342
343impl<'a, V> Expr<'a, V> for SQLBytes<'a>
344where
345    V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + Into<Cow<'a, V>>,
346{
347    type SQLType = <V::DialectMarker as DialectTypes>::Bytes;
348    type Nullable = NonNull;
349    type Aggregate = Scalar;
350
351    fn to_expr_sql(&self) -> SQL<'a, V> {
352        match &self.0 {
353            Cow::Borrowed(value) => SQL::bytes(*value),
354            Cow::Owned(value) => SQL::bytes(value.clone()),
355        }
356    }
357
358    fn into_expr_sql(self) -> SQL<'a, V> {
359        SQL::bytes(self.0)
360    }
361}
362
363// =============================================================================
364// Option<T> - Makes Any Expression Nullable
365// =============================================================================
366
367impl<'a, V, T> Expr<'a, V> for Option<T>
368where
369    V: SQLParam + 'a,
370    T: Expr<'a, V>,
371    T::Nullable: Nullability,
372{
373    type SQLType = T::SQLType;
374    type Nullable = Null;
375    type Aggregate = T::Aggregate;
376
377    /// A missing optional condition contributes nothing to a condition list.
378    fn to_condition_sql(&self) -> Option<SQL<'a, V>> {
379        self.as_ref().map(<T as Expr<'a, V>>::to_expr_sql)
380    }
381
382    /// A missing optional condition contributes nothing to a condition list.
383    fn into_condition_sql(self) -> Option<SQL<'a, V>> {
384        self.map(<T as Expr<'a, V>>::into_expr_sql)
385    }
386}
387
388// =============================================================================
389// Reference Types - Delegate to Inner
390// =============================================================================
391
392impl<'a, V, T> Expr<'a, V> for &T
393where
394    V: SQLParam + 'a,
395    T: Expr<'a, V>,
396    T::Nullable: Nullability,
397{
398    type SQLType = T::SQLType;
399    type Nullable = T::Nullable;
400    type Aggregate = T::Aggregate;
401
402    fn to_expr_sql(&self) -> SQL<'a, V> {
403        (**self).to_expr_sql()
404    }
405
406    fn into_expr_sql(self) -> SQL<'a, V> {
407        (*self).to_expr_sql()
408    }
409
410    fn to_condition_sql(&self) -> Option<SQL<'a, V>> {
411        (**self).to_condition_sql()
412    }
413
414    fn into_condition_sql(self) -> Option<SQL<'a, V>> {
415        (*self).to_condition_sql()
416    }
417}
418
419// =============================================================================
420// UUID (Feature-Gated)
421// =============================================================================
422
423#[cfg(feature = "uuid")]
424impl<'a, V> Expr<'a, V> for uuid::Uuid
425where
426    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
427{
428    type SQLType = <V::DialectMarker as DialectTypes>::Uuid;
429    type Nullable = NonNull;
430    type Aggregate = Scalar;
431}
432
433#[cfg(feature = "rust-decimal")]
434impl<'a, V> Expr<'a, V> for rust_decimal::Decimal
435where
436    V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
437    Self: ValueTypeForDialect<V::DialectMarker>,
438{
439    type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
440    type Nullable = NonNull;
441    type Aggregate = Scalar;
442}
443
444// =============================================================================
445// Date and Time Values (Feature-Gated)
446// =============================================================================
447
448/// Lets a date or time value stand where an expression goes (`eq(col, value)`,
449/// `gt(col, value)`), typed as the SQL type its dialect stores it as.
450#[cfg(any(feature = "chrono", feature = "time", feature = "jiff"))]
451macro_rules! impl_value_expr {
452    ($($ty:ty),+ $(,)?) => {$(
453        impl<'a, V> Expr<'a, V> for $ty
454        where
455            V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
456            Self: ValueTypeForDialect<V::DialectMarker>,
457        {
458            type SQLType = <Self as ValueTypeForDialect<V::DialectMarker>>::SQLType;
459            type Nullable = NonNull;
460            type Aggregate = Scalar;
461        }
462    )+};
463}
464
465#[cfg(feature = "chrono")]
466impl_value_expr!(
467    chrono::NaiveDate,
468    chrono::NaiveTime,
469    chrono::NaiveDateTime,
470    chrono::DateTime<chrono::Utc>,
471    chrono::DateTime<chrono::FixedOffset>,
472    chrono::Duration,
473);
474
475#[cfg(feature = "time")]
476impl_value_expr!(
477    time::Date,
478    time::Time,
479    time::PrimitiveDateTime,
480    time::OffsetDateTime,
481    time::Duration,
482);
483
484#[cfg(feature = "jiff")]
485impl_value_expr!(
486    jiff::civil::Date,
487    jiff::civil::Time,
488    jiff::civil::DateTime,
489    jiff::Timestamp,
490);
491
492// =============================================================================
493// SQL Type - Backward Compatibility
494// Allows untyped columns (which return SQL) to work with typed functions.
495// =============================================================================
496
497impl<'a, V> Expr<'a, V> for crate::sql::SQL<'a, V>
498where
499    V: SQLParam + 'a,
500{
501    type SQLType = <V::DialectMarker as DialectTypes>::Any;
502    type Nullable = Null;
503    type Aggregate = Scalar;
504}