Skip to main content

qraft_core/
compat.rs

1use std::{borrow::Cow, rc::Rc, sync::Arc};
2
3#[cfg(feature = "chrono")]
4use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Utc};
5use quex::{
6    Date as QuexDate, DateTime as QuexDateTime, DateTimeTz as QuexDateTimeTz, Encode,
7    Time as QuexTime,
8};
9#[cfg(feature = "serde_json")]
10use serde_json::Value as JsonValue;
11#[cfg(feature = "uuid")]
12use uuid::Uuid;
13
14use crate::{
15    BigInt, Blob, Bool, Date, Double, Float, Int, Nullable, Text, Time, Timestamp, UBigInt, UInt,
16    expression::{AsExpression, Expression},
17    lower::LowerCtx,
18    param::encode_param,
19    ty::TypeMeta,
20};
21
22/// Default SQL marker type for a Rust value.
23pub trait DefaultMeta {
24    type Meta: TypeMeta;
25}
26
27/// Explicit typed compatibility between a Rust value and a qraft SQL type.
28pub trait Compatible<T: TypeMeta>: Encode {}
29
30/// Internal lowering bridge used by operator APIs.
31#[doc(hidden)]
32pub trait LowerCompatible<T: TypeMeta> {
33    fn lower_compatible(&self, ctx: &mut LowerCtx) -> usize;
34}
35
36impl<T> DefaultMeta for Option<T>
37where
38    T: DefaultMeta,
39{
40    type Meta = Nullable<T::Meta>;
41}
42
43impl<T> DefaultMeta for &T
44where
45    T: DefaultMeta + ?Sized,
46{
47    type Meta = T::Meta;
48}
49
50impl<T, U> Compatible<T> for &U
51where
52    T: TypeMeta,
53    U: Compatible<T> + ?Sized,
54{
55}
56
57impl<T, V> LowerCompatible<T> for V
58where
59    T: TypeMeta,
60    V: Compatible<T> + ?Sized,
61{
62    fn lower_compatible(&self, ctx: &mut LowerCtx) -> usize {
63        let param = encode_param(self, ctx.data);
64        ctx.lower_param(param)
65    }
66}
67
68macro_rules! impl_text_lower_compatible {
69    ($($ty:ty),+ $(,)?) => {
70        $(
71            impl LowerCompatible<Text> for $ty {
72                fn lower_compatible(&self, ctx: &mut LowerCtx) -> usize {
73                    let param = encode_param(self.as_ref(), ctx.data);
74                    ctx.lower_param(param)
75                }
76            }
77
78            impl LowerCompatible<Nullable<Text>> for $ty {
79                fn lower_compatible(&self, ctx: &mut LowerCtx) -> usize {
80                    let param = encode_param(self.as_ref(), ctx.data);
81                    ctx.lower_param(param)
82                }
83            }
84        )+
85    };
86}
87
88impl_text_lower_compatible!(Box<str>, Arc<str>, Rc<str>, Cow<'_, str>);
89
90macro_rules! impl_blob_lower_compatible {
91    ($($ty:ty),+ $(,)?) => {
92        $(
93            impl LowerCompatible<Blob> for $ty {
94                fn lower_compatible(&self, ctx: &mut LowerCtx) -> usize {
95                    let param = encode_param(self.as_ref(), ctx.data);
96                    ctx.lower_param(param)
97                }
98            }
99
100            impl LowerCompatible<Nullable<Blob>> for $ty {
101                fn lower_compatible(&self, ctx: &mut LowerCtx) -> usize {
102                    let param = encode_param(self.as_ref(), ctx.data);
103                    ctx.lower_param(param)
104                }
105            }
106        )+
107    };
108}
109
110impl_blob_lower_compatible!(Box<[u8]>, Arc<[u8]>, Rc<[u8]>, Cow<'_, [u8]>);
111
112impl<T, U> AsExpression<T> for &U
113where
114    T: TypeMeta,
115    U: AsExpression<T> + ?Sized,
116{
117    type Expression<'e>
118        = U::Expression<'e>
119    where
120        Self: 'e;
121
122    fn as_expression<'e>(&'e self) -> Self::Expression<'e> {
123        U::as_expression(*self)
124    }
125}
126
127macro_rules! impl_default_meta {
128    ($meta:ty => $($ty:ty),+ $(,)?) => {
129        $(impl DefaultMeta for $ty {
130            type Meta = $meta;
131        })+
132    };
133}
134
135impl_default_meta!(Text => String, str, Box<str>, Arc<str>, Rc<str>, Cow<'_, str>);
136impl_default_meta!(Blob => Vec<u8>, [u8], Box<[u8]>, Arc<[u8]>, Rc<[u8]>, Cow<'_, [u8]>);
137impl_default_meta!(Bool => bool);
138impl_default_meta!(Int => i8, i16, i32);
139impl_default_meta!(BigInt => i64);
140impl_default_meta!(UInt => u8, u16, u32);
141impl_default_meta!(UBigInt => u64);
142impl_default_meta!(Float => f32);
143impl_default_meta!(Double => f64);
144impl_default_meta!(Date => QuexDate);
145impl_default_meta!(Time => QuexTime);
146impl_default_meta!(Timestamp => QuexDateTime, QuexDateTimeTz);
147#[cfg(feature = "chrono")]
148impl_default_meta!(Date => NaiveDate);
149#[cfg(feature = "chrono")]
150impl_default_meta!(Time => NaiveTime);
151#[cfg(feature = "chrono")]
152impl_default_meta!(Timestamp => NaiveDateTime, DateTime<Utc>, DateTime<FixedOffset>);
153#[cfg(feature = "uuid")]
154impl_default_meta!(Text => Uuid);
155#[cfg(feature = "serde_json")]
156impl_default_meta!(Text => JsonValue);
157
158macro_rules! impl_compatible_exact {
159    ($sql:ty => $($ty:ty),+ $(,)?) => {
160        $(
161            impl Compatible<$sql> for $ty {}
162            impl Compatible<Nullable<$sql>> for $ty {}
163        )+
164    };
165}
166
167impl_compatible_exact!(Int => i8, i16, i32);
168impl_compatible_exact!(BigInt => i64);
169impl_compatible_exact!(UInt => u8, u16, u32);
170impl_compatible_exact!(UBigInt => u64);
171impl_compatible_exact!(Bool => bool);
172impl_compatible_exact!(Float => f32);
173impl_compatible_exact!(Double => f64);
174impl_compatible_exact!(Date => QuexDate);
175impl_compatible_exact!(Time => QuexTime);
176impl_compatible_exact!(Timestamp => QuexDateTime, QuexDateTimeTz);
177
178macro_rules! impl_compatible_bigint_widen {
179    ($($ty:ty),+ $(,)?) => {
180        $(
181            impl Compatible<BigInt> for $ty {}
182            impl Compatible<Nullable<BigInt>> for $ty {}
183        )+
184    };
185}
186
187impl_compatible_bigint_widen!(i8, i16, i32);
188
189impl Compatible<Double> for f32 {}
190impl Compatible<Nullable<Double>> for f32 {}
191
192macro_rules! impl_text_compatible {
193    ($($ty:ty),+ $(,)?) => {
194        $(
195            impl Compatible<Text> for $ty {}
196            impl Compatible<Nullable<Text>> for $ty {}
197        )+
198    };
199}
200
201impl_text_compatible!(str, String);
202
203macro_rules! impl_blob_compatible {
204    ($($ty:ty),+ $(,)?) => {
205        $(
206            impl Compatible<Blob> for $ty {}
207            impl Compatible<Nullable<Blob>> for $ty {}
208        )+
209    };
210}
211
212impl_blob_compatible!([u8], Vec<u8>);
213
214#[cfg(feature = "chrono")]
215impl Compatible<Date> for NaiveDate {}
216#[cfg(feature = "chrono")]
217impl Compatible<Nullable<Date>> for NaiveDate {}
218#[cfg(feature = "chrono")]
219impl Compatible<Time> for NaiveTime {}
220#[cfg(feature = "chrono")]
221impl Compatible<Nullable<Time>> for NaiveTime {}
222#[cfg(feature = "chrono")]
223impl Compatible<Timestamp> for NaiveDateTime {}
224#[cfg(feature = "chrono")]
225impl Compatible<Nullable<Timestamp>> for NaiveDateTime {}
226#[cfg(feature = "chrono")]
227impl Compatible<Timestamp> for DateTime<FixedOffset> {}
228#[cfg(feature = "chrono")]
229impl Compatible<Nullable<Timestamp>> for DateTime<FixedOffset> {}
230#[cfg(feature = "chrono")]
231impl Compatible<Timestamp> for DateTime<Utc> {}
232#[cfg(feature = "chrono")]
233impl Compatible<Nullable<Timestamp>> for DateTime<Utc> {}
234
235#[cfg(feature = "uuid")]
236impl Compatible<Text> for Uuid {}
237#[cfg(feature = "uuid")]
238impl Compatible<Nullable<Text>> for Uuid {}
239
240#[cfg(feature = "serde_json")]
241impl Compatible<Text> for JsonValue {}
242#[cfg(feature = "serde_json")]
243impl Compatible<Nullable<Text>> for JsonValue {}
244
245impl<T, V> Compatible<Nullable<T>> for Option<V>
246where
247    T: TypeMeta,
248    V: Compatible<T>,
249{
250}
251
252pub struct TypedParam<'e, T: TypeMeta, V: ?Sized> {
253    value: &'e V,
254    marker: std::marker::PhantomData<T>,
255}
256
257impl<'e, T: TypeMeta, V: ?Sized> TypedParam<'e, T, V> {
258    pub fn new(value: &'e V) -> Self {
259        Self {
260            value,
261            marker: std::marker::PhantomData,
262        }
263    }
264}
265
266impl<T, V> Expression for TypedParam<'_, T, V>
267where
268    T: TypeMeta,
269    V: Compatible<T> + ?Sized,
270{
271    type Type = T;
272
273    fn lower(&self, ctx: &mut LowerCtx) -> usize {
274        self.value.lower_compatible(ctx)
275    }
276}
277
278macro_rules! impl_as_expression {
279    ($sql:ty => $($ty:ty),+ $(,)?) => {
280        $(
281            impl AsExpression<$sql> for $ty {
282                type Expression<'e>
283                    = TypedParam<'e, $sql, $ty>
284                where
285                    Self: 'e;
286
287                fn as_expression<'e>(&'e self) -> Self::Expression<'e> {
288                    TypedParam::new(self)
289                }
290            }
291
292            impl AsExpression<Nullable<$sql>> for $ty {
293                type Expression<'e>
294                    = TypedParam<'e, Nullable<$sql>, $ty>
295                where
296                    Self: 'e;
297
298                fn as_expression<'e>(&'e self) -> Self::Expression<'e> {
299                    TypedParam::new(self)
300                }
301            }
302        )+
303    };
304}
305
306impl_as_expression!(Bool => bool);
307impl_as_expression!(Int => i8, i16, i32);
308impl_as_expression!(BigInt => i8, i16, i32, i64);
309impl_as_expression!(UInt => u8, u16, u32);
310impl_as_expression!(UBigInt => u64);
311impl_as_expression!(Float => f32);
312impl_as_expression!(Double => f32, f64);
313impl_as_expression!(Text => str, String);
314impl_as_expression!(Blob => [u8], Vec<u8>);
315impl_as_expression!(Date => QuexDate);
316impl_as_expression!(Time => QuexTime);
317impl_as_expression!(Timestamp => QuexDateTime, QuexDateTimeTz);
318#[cfg(feature = "chrono")]
319impl_as_expression!(Date => NaiveDate);
320#[cfg(feature = "chrono")]
321impl_as_expression!(Time => NaiveTime);
322#[cfg(feature = "chrono")]
323impl_as_expression!(Timestamp => NaiveDateTime, DateTime<Utc>, DateTime<FixedOffset>);
324#[cfg(feature = "uuid")]
325impl_as_expression!(Text => Uuid);
326#[cfg(feature = "serde_json")]
327impl_as_expression!(Text => JsonValue);
328
329impl<T, V> AsExpression<Nullable<T>> for Option<V>
330where
331    T: TypeMeta,
332    V: Compatible<T>,
333{
334    type Expression<'e>
335        = TypedParam<'e, Nullable<T>, Option<V>>
336    where
337        Self: 'e;
338
339    fn as_expression<'e>(&'e self) -> Self::Expression<'e> {
340        TypedParam::new(self)
341    }
342}